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

« back to all changes in this revision

Viewing changes to subversion/libsvn_client/commit_util.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:
44
44
 
45
45
#include "svn_private_config.h"
46
46
#include "private/svn_wc_private.h"
 
47
#include "private/svn_client_private.h"
47
48
 
48
49
/*** Uncomment this to turn on commit driver debugging. ***/
49
50
/*
181
182
 
182
183
/* Add a new commit candidate (described by all parameters except
183
184
   `COMMITTABLES') to the COMMITTABLES hash.  All of the commit item's
184
 
   members are allocated out of RESULT_POOL. */
 
185
   members are allocated out of RESULT_POOL.
 
186
 
 
187
   If the state flag specifies that a lock must be used, store the token in LOCK
 
188
   in lock_tokens.
 
189
 */
185
190
static svn_error_t *
186
191
add_committable(svn_client__committables_t *committables,
187
192
                const char *local_abspath,
191
196
                svn_revnum_t revision,
192
197
                const char *copyfrom_relpath,
193
198
                svn_revnum_t copyfrom_rev,
 
199
                const char *moved_from_abspath,
194
200
                apr_byte_t state_flags,
 
201
                apr_hash_t *lock_tokens,
 
202
                const svn_lock_t *lock,
195
203
                apr_pool_t *result_pool,
196
204
                apr_pool_t *scratch_pool)
197
205
{
205
213
  /* ### todo: Get the canonical repository for this item, which will
206
214
     be the real key for the COMMITTABLES hash, instead of the above
207
215
     bogosity. */
208
 
  array = apr_hash_get(committables->by_repository,
209
 
                       repos_root_url,
210
 
                       APR_HASH_KEY_STRING);
 
216
  array = svn_hash_gets(committables->by_repository, repos_root_url);
211
217
 
212
218
  /* E-gads!  There is no array for this repository yet!  Oh, no
213
219
     problem, we'll just create (and add to the hash) one. */
214
220
  if (array == NULL)
215
221
    {
216
222
      array = apr_array_make(result_pool, 1, sizeof(new_item));
217
 
      apr_hash_set(committables->by_repository,
218
 
                   apr_pstrdup(result_pool, repos_root_url),
219
 
                   APR_HASH_KEY_STRING, array);
 
223
      svn_hash_sets(committables->by_repository,
 
224
                    apr_pstrdup(result_pool, repos_root_url), array);
220
225
    }
221
226
 
222
227
  /* Now update pointer values, ensuring that their allocations live
238
243
  new_item->incoming_prop_changes = apr_array_make(result_pool, 1,
239
244
                                                   sizeof(svn_prop_t *));
240
245
 
 
246
  if (moved_from_abspath)
 
247
    new_item->moved_from_abspath = apr_pstrdup(result_pool,
 
248
                                               moved_from_abspath);
 
249
 
241
250
  /* Now, add the commit item to the array. */
242
251
  APR_ARRAY_PUSH(array, svn_client_commit_item3_t *) = new_item;
243
252
 
244
253
  /* ... and to the hash. */
245
 
  apr_hash_set(committables->by_path,
246
 
               new_item->path,
247
 
               APR_HASH_KEY_STRING,
248
 
               new_item);
 
254
  svn_hash_sets(committables->by_path, new_item->path, new_item);
 
255
 
 
256
  if (lock
 
257
      && lock_tokens
 
258
      && (state_flags & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN))
 
259
    {
 
260
      svn_hash_sets(lock_tokens, new_item->url,
 
261
                    apr_pstrdup(result_pool, lock->token));
 
262
    }
249
263
 
250
264
  return SVN_NO_ERROR;
251
265
}
258
272
                    apr_pool_t *pool)
259
273
{
260
274
  return (svn_client_commit_item3_t *)
261
 
      apr_hash_get(committables->by_path, path, APR_HASH_KEY_STRING);
262
 
}
263
 
 
264
 
/* Helper for harvest_committables().
265
 
 * If ENTRY is a dir, return an SVN_ERR_WC_FOUND_CONFLICT error when
266
 
 * encountering a tree-conflicted immediate child node. However, do
267
 
 * not consider immediate children that are outside the bounds of DEPTH.
268
 
 *
269
 
 * TODO ### WC_CTX and LOCAL_ABSPATH ...
270
 
 * ENTRY, DEPTH, CHANGELISTS and POOL are the same ones
271
 
 * originally received by harvest_committables().
272
 
 *
273
 
 * Tree-conflicts information is stored in the victim's immediate parent.
274
 
 * In some cases of an absent tree-conflicted victim, the tree-conflict
275
 
 * information in its parent dir is the only indication that the node
276
 
 * is under version control. This function is necessary for this
277
 
 * particular case. In all other cases, this simply bails out a little
278
 
 * bit earlier. */
279
 
static svn_error_t *
280
 
bail_on_tree_conflicted_children(svn_wc_context_t *wc_ctx,
281
 
                                 const char *local_abspath,
282
 
                                 svn_node_kind_t kind,
283
 
                                 svn_depth_t depth,
284
 
                                 apr_hash_t *changelists,
285
 
                                 svn_wc_notify_func2_t notify_func,
286
 
                                 void *notify_baton,
287
 
                                 apr_pool_t *pool)
288
 
{
289
 
  apr_hash_t *conflicts;
290
 
  apr_hash_index_t *hi;
291
 
 
292
 
  if ((depth == svn_depth_empty)
293
 
      || (kind != svn_node_dir))
294
 
    /* There can't possibly be tree-conflicts information here. */
295
 
    return SVN_NO_ERROR;
296
 
 
297
 
  SVN_ERR(svn_wc__get_all_tree_conflicts(&conflicts, wc_ctx, local_abspath,
298
 
                                         pool, pool));
299
 
  if (!conflicts)
300
 
    return SVN_NO_ERROR;
301
 
 
302
 
  for (hi = apr_hash_first(pool, conflicts); hi; hi = apr_hash_next(hi))
303
 
    {
304
 
      const svn_wc_conflict_description2_t *conflict =
305
 
          svn__apr_hash_index_val(hi);
306
 
 
307
 
      if ((conflict->node_kind == svn_node_dir) &&
308
 
          (depth == svn_depth_files))
309
 
        continue;
310
 
 
311
 
      /* So we've encountered a conflict that is included in DEPTH.
312
 
         Bail out. But if there are CHANGELISTS, avoid bailing out
313
 
         on an item that doesn't match the CHANGELISTS. */
314
 
      if (!svn_wc__changelist_match(wc_ctx, local_abspath, changelists, pool))
315
 
        continue;
316
 
 
317
 
      /* At this point, a conflict was found, and either there were no
318
 
         changelists, or the changelists matched. Bail out already! */
319
 
 
320
 
      if (notify_func != NULL)
321
 
        {
322
 
          notify_func(notify_baton,
323
 
                      svn_wc_create_notify(local_abspath,
324
 
                                           svn_wc_notify_failed_conflict,
325
 
                                           pool),
326
 
                      pool);
327
 
        }
328
 
 
329
 
      return svn_error_createf(
330
 
               SVN_ERR_WC_FOUND_CONFLICT, NULL,
331
 
               _("Aborting commit: '%s' remains in conflict"),
332
 
               svn_dirent_local_style(conflict->local_abspath, pool));
333
 
    }
334
 
 
335
 
  return SVN_NO_ERROR;
 
275
      svn_hash_gets(committables->by_path, path);
336
276
}
337
277
 
338
278
/* Helper function for svn_client__harvest_committables().
347
287
{
348
288
  const char *wcroot_abspath;
349
289
 
350
 
  SVN_ERR(svn_wc__get_wc_root(&wcroot_abspath, wc_ctx, local_abspath,
351
 
                              scratch_pool, scratch_pool));
 
290
  SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath, wc_ctx, local_abspath,
 
291
                             scratch_pool, scratch_pool));
352
292
 
353
293
  local_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
354
294
 
402
342
   If COMMIT_RELPATH is not NULL, treat not-added nodes as if it is destined to
403
343
   be added as COMMIT_RELPATH, and add 'deleted' entries to COMMITTABLES as
404
344
   items to delete in the copy destination.  COPY_MODE_ROOT should be set TRUE
405
 
   for the first call for which COPY_MODE is TRUE, i.e. not for for the
 
345
   for the first call for which COPY_MODE is TRUE, i.e. not for the
406
346
   recursive calls, and FALSE otherwise.
407
347
 
408
348
   If CHANGELISTS is non-NULL, it is a hash whose keys are const char *
410
350
   when harvesting committables; that is, don't add a path to
411
351
   COMMITTABLES unless it's a member of one of those changelists.
412
352
 
 
353
   IS_EXPLICIT_TARGET should always be passed as TRUE, except when
 
354
   harvest_committables() calls itself in recursion. This provides a way to
 
355
   tell whether LOCAL_ABSPATH was an original target or whether it was reached
 
356
   by recursing deeper into a dir target. (This is used to skip all file
 
357
   externals that aren't explicit commit targets.)
 
358
 
413
359
   DANGLERS is a hash table mapping const char* absolute paths of a parent
414
360
   to a const char * absolute path of a child. See the comment about
415
361
   danglers at the top of svn_client__harvest_committables().
419
365
 
420
366
   Any items added to COMMITTABLES are allocated from the COMITTABLES
421
367
   hash pool, not POOL.  SCRATCH_POOL is used for temporary allocations. */
422
 
static svn_error_t *
423
 
harvest_committables(svn_wc_context_t *wc_ctx,
424
 
                     const char *local_abspath,
 
368
 
 
369
struct harvest_baton
 
370
{
 
371
  /* Static data */
 
372
  const char *root_abspath;
 
373
  svn_client__committables_t *committables;
 
374
  apr_hash_t *lock_tokens;
 
375
  const char *commit_relpath; /* Valid for the harvest root */
 
376
  svn_depth_t depth;
 
377
  svn_boolean_t just_locked;
 
378
  apr_hash_t *changelists;
 
379
  apr_hash_t *danglers;
 
380
  svn_client__check_url_kind_t check_url_func;
 
381
  void *check_url_baton;
 
382
  svn_wc_notify_func2_t notify_func;
 
383
  void *notify_baton;
 
384
  svn_wc_context_t *wc_ctx;
 
385
  apr_pool_t *result_pool;
 
386
 
 
387
  /* Harvester state */
 
388
  const char *skip_below_abspath; /* If non-NULL, skip everything below */
 
389
};
 
390
 
 
391
static svn_error_t *
 
392
harvest_status_callback(void *status_baton,
 
393
                        const char *local_abspath,
 
394
                        const svn_wc_status3_t *status,
 
395
                        apr_pool_t *scratch_pool);
 
396
 
 
397
static svn_error_t *
 
398
harvest_committables(const char *local_abspath,
425
399
                     svn_client__committables_t *committables,
426
400
                     apr_hash_t *lock_tokens,
427
 
                     const char *repos_root_url,
428
 
                     const char *commit_relpath,
429
 
                     svn_boolean_t copy_mode_root,
 
401
                     const char *copy_mode_relpath,
430
402
                     svn_depth_t depth,
431
403
                     svn_boolean_t just_locked,
432
404
                     apr_hash_t *changelists,
433
 
                     svn_boolean_t skip_files,
434
 
                     svn_boolean_t skip_dirs,
435
405
                     apr_hash_t *danglers,
436
406
                     svn_client__check_url_kind_t check_url_func,
437
407
                     void *check_url_baton,
439
409
                     void *cancel_baton,
440
410
                     svn_wc_notify_func2_t notify_func,
441
411
                     void *notify_baton,
 
412
                     svn_wc_context_t *wc_ctx,
442
413
                     apr_pool_t *result_pool,
443
414
                     apr_pool_t *scratch_pool)
444
415
{
445
 
  svn_boolean_t text_mod = FALSE;
446
 
  svn_boolean_t prop_mod = FALSE;
 
416
  struct harvest_baton baton;
 
417
 
 
418
  SVN_ERR_ASSERT((just_locked && lock_tokens) || !just_locked);
 
419
 
 
420
  baton.root_abspath = local_abspath;
 
421
  baton.committables = committables;
 
422
  baton.lock_tokens = lock_tokens;
 
423
  baton.commit_relpath = copy_mode_relpath;
 
424
  baton.depth = depth;
 
425
  baton.just_locked = just_locked;
 
426
  baton.changelists = changelists;
 
427
  baton.danglers = danglers;
 
428
  baton.check_url_func = check_url_func;
 
429
  baton.check_url_baton = check_url_baton;
 
430
  baton.notify_func = notify_func;
 
431
  baton.notify_baton = notify_baton;
 
432
  baton.wc_ctx = wc_ctx;
 
433
  baton.result_pool = result_pool;
 
434
 
 
435
  baton.skip_below_abspath = NULL;
 
436
 
 
437
  SVN_ERR(svn_wc_walk_status(wc_ctx,
 
438
                             local_abspath,
 
439
                             depth,
 
440
                             (copy_mode_relpath != NULL) /* get_all */,
 
441
                             FALSE /* no_ignore */,
 
442
                             FALSE /* ignore_text_mods */,
 
443
                             NULL /* ignore_patterns */,
 
444
                             harvest_status_callback,
 
445
                             &baton,
 
446
                             cancel_func, cancel_baton,
 
447
                             scratch_pool));
 
448
 
 
449
  return SVN_NO_ERROR;
 
450
}
 
451
 
 
452
static svn_error_t *
 
453
harvest_not_present_for_copy(svn_wc_context_t *wc_ctx,
 
454
                             const char *local_abspath,
 
455
                             svn_client__committables_t *committables,
 
456
                             const char *repos_root_url,
 
457
                             const char *commit_relpath,
 
458
                             svn_client__check_url_kind_t check_url_func,
 
459
                             void *check_url_baton,
 
460
                             apr_pool_t *result_pool,
 
461
                             apr_pool_t *scratch_pool)
 
462
{
 
463
  const apr_array_header_t *children;
 
464
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
465
  int i;
 
466
 
 
467
  /* A function to retrieve not present children would be nice to have */
 
468
  SVN_ERR(svn_wc__node_get_children_of_working_node(
 
469
                                    &children, wc_ctx, local_abspath, TRUE,
 
470
                                    scratch_pool, iterpool));
 
471
 
 
472
  for (i = 0; i < children->nelts; i++)
 
473
    {
 
474
      const char *this_abspath = APR_ARRAY_IDX(children, i, const char *);
 
475
      const char *name = svn_dirent_basename(this_abspath, NULL);
 
476
      const char *this_commit_relpath;
 
477
      svn_boolean_t not_present;
 
478
      svn_node_kind_t kind;
 
479
 
 
480
      svn_pool_clear(iterpool);
 
481
 
 
482
      SVN_ERR(svn_wc__node_is_not_present(&not_present, NULL, NULL, wc_ctx,
 
483
                                          this_abspath, FALSE, scratch_pool));
 
484
 
 
485
      if (!not_present)
 
486
        continue;
 
487
 
 
488
      if (commit_relpath == NULL)
 
489
        this_commit_relpath = NULL;
 
490
      else
 
491
        this_commit_relpath = svn_relpath_join(commit_relpath, name,
 
492
                                              iterpool);
 
493
 
 
494
      /* We should check if we should really add a delete operation */
 
495
      if (check_url_func)
 
496
        {
 
497
          svn_revnum_t parent_rev;
 
498
          const char *parent_repos_relpath;
 
499
          const char *parent_repos_root_url;
 
500
          const char *node_url;
 
501
 
 
502
          /* Determine from what parent we would be the deleted child */
 
503
          SVN_ERR(svn_wc__node_get_origin(
 
504
                              NULL, &parent_rev, &parent_repos_relpath,
 
505
                              &parent_repos_root_url, NULL, NULL,
 
506
                              wc_ctx,
 
507
                              svn_dirent_dirname(this_abspath,
 
508
                                                  scratch_pool),
 
509
                              FALSE, scratch_pool, scratch_pool));
 
510
 
 
511
          node_url = svn_path_url_add_component2(
 
512
                        svn_path_url_add_component2(parent_repos_root_url,
 
513
                                                    parent_repos_relpath,
 
514
                                                    scratch_pool),
 
515
                        svn_dirent_basename(this_abspath, NULL),
 
516
                        iterpool);
 
517
 
 
518
          SVN_ERR(check_url_func(check_url_baton, &kind,
 
519
                                 node_url, parent_rev, iterpool));
 
520
 
 
521
          if (kind == svn_node_none)
 
522
            continue; /* This node can't be deleted */
 
523
        }
 
524
      else
 
525
        SVN_ERR(svn_wc_read_kind2(&kind, wc_ctx, this_abspath,
 
526
                                  TRUE, TRUE, scratch_pool));
 
527
 
 
528
      SVN_ERR(add_committable(committables, this_abspath, kind,
 
529
                              repos_root_url,
 
530
                              this_commit_relpath,
 
531
                              SVN_INVALID_REVNUM,
 
532
                              NULL /* copyfrom_relpath */,
 
533
                              SVN_INVALID_REVNUM /* copyfrom_rev */,
 
534
                              NULL /* moved_from_abspath */,
 
535
                              SVN_CLIENT_COMMIT_ITEM_DELETE,
 
536
                              NULL, NULL,
 
537
                              result_pool, scratch_pool));
 
538
    }
 
539
 
 
540
  svn_pool_destroy(iterpool);
 
541
  return SVN_NO_ERROR;
 
542
}
 
543
 
 
544
/* Implements svn_wc_status_func4_t */
 
545
static svn_error_t *
 
546
harvest_status_callback(void *status_baton,
 
547
                        const char *local_abspath,
 
548
                        const svn_wc_status3_t *status,
 
549
                        apr_pool_t *scratch_pool)
 
550
{
447
551
  apr_byte_t state_flags = 0;
448
 
  svn_node_kind_t working_kind;
449
 
  svn_node_kind_t db_kind;
450
 
  const char *node_relpath;
451
 
  const char *node_lock_token;
452
552
  svn_revnum_t node_rev;
453
553
  const char *cf_relpath = NULL;
454
554
  svn_revnum_t cf_rev = SVN_INVALID_REVNUM;
455
555
  svn_boolean_t matches_changelists;
456
 
  svn_boolean_t is_special;
457
556
  svn_boolean_t is_added;
458
557
  svn_boolean_t is_deleted;
459
558
  svn_boolean_t is_replaced;
460
 
  svn_boolean_t is_not_present;
461
 
  svn_boolean_t is_excluded;
462
559
  svn_boolean_t is_op_root;
463
 
  svn_boolean_t is_symlink;
464
 
  svn_boolean_t conflicted;
465
 
  const char *node_changelist;
466
 
  svn_boolean_t is_update_root;
467
560
  svn_revnum_t original_rev;
468
561
  const char *original_relpath;
469
 
  svn_boolean_t copy_mode = (commit_relpath != NULL);
470
 
 
471
 
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
562
  svn_boolean_t copy_mode;
 
563
 
 
564
  struct harvest_baton *baton = status_baton;
 
565
  svn_boolean_t is_harvest_root =
 
566
                (strcmp(baton->root_abspath, local_abspath) == 0);
 
567
  svn_client__committables_t *committables = baton->committables;
 
568
  const char *repos_root_url = status->repos_root_url;
 
569
  const char *commit_relpath = NULL;
 
570
  svn_boolean_t copy_mode_root = (baton->commit_relpath && is_harvest_root);
 
571
  svn_boolean_t just_locked = baton->just_locked;
 
572
  apr_hash_t *changelists = baton->changelists;
 
573
  svn_wc_notify_func2_t notify_func = baton->notify_func;
 
574
  void *notify_baton = baton->notify_baton;
 
575
  svn_wc_context_t *wc_ctx = baton->wc_ctx;
 
576
  apr_pool_t *result_pool = baton->result_pool;
 
577
  const char *moved_from_abspath = NULL;
 
578
 
 
579
  if (baton->commit_relpath)
 
580
    commit_relpath = svn_relpath_join(
 
581
                        baton->commit_relpath,
 
582
                        svn_dirent_skip_ancestor(baton->root_abspath,
 
583
                                                 local_abspath),
 
584
                        scratch_pool);
 
585
 
 
586
  copy_mode = (commit_relpath != NULL);
 
587
 
 
588
  if (baton->skip_below_abspath
 
589
      && svn_dirent_is_ancestor(baton->skip_below_abspath, local_abspath))
 
590
    {
 
591
      return SVN_NO_ERROR;
 
592
    }
 
593
  else
 
594
    baton->skip_below_abspath = NULL; /* We have left the skip tree */
 
595
 
 
596
  /* Return early for nodes that don't have a committable status */
 
597
  switch (status->node_status)
 
598
    {
 
599
      case svn_wc_status_unversioned:
 
600
      case svn_wc_status_ignored:
 
601
      case svn_wc_status_external:
 
602
      case svn_wc_status_none:
 
603
        /* Unversioned nodes aren't committable, but are reported by the status
 
604
           walker.
 
605
           But if the unversioned node is the root of the walk, we have a user
 
606
           error */
 
607
        if (is_harvest_root)
 
608
          return svn_error_createf(
 
609
                       SVN_ERR_ILLEGAL_TARGET, NULL,
 
610
                       _("'%s' is not under version control"),
 
611
                       svn_dirent_local_style(local_abspath, scratch_pool));
 
612
        return SVN_NO_ERROR;
 
613
      case svn_wc_status_normal:
 
614
        /* Status normal nodes aren't modified, so we don't have to commit them
 
615
           when we perform a normal commit. But if a node is conflicted we want
 
616
           to stop the commit and if we are collecting lock tokens we want to
 
617
           look further anyway.
 
618
 
 
619
           When in copy mode we need to compare the revision of the node against
 
620
           the parent node to copy mixed-revision base nodes properly */
 
621
        if (!copy_mode && !status->conflicted
 
622
            && !(just_locked && status->lock))
 
623
          return SVN_NO_ERROR;
 
624
        break;
 
625
      default:
 
626
        /* Fall through */
 
627
        break;
 
628
    }
472
629
 
473
630
  /* Early out if the item is already marked as committable. */
474
631
  if (look_up_committable(committables, local_abspath, scratch_pool))
477
634
  SVN_ERR_ASSERT((copy_mode && commit_relpath)
478
635
                 || (! copy_mode && ! commit_relpath));
479
636
  SVN_ERR_ASSERT((copy_mode_root && copy_mode) || ! copy_mode_root);
480
 
  SVN_ERR_ASSERT((just_locked && lock_tokens) || !just_locked);
481
 
 
482
 
  if (cancel_func)
483
 
    SVN_ERR(cancel_func(cancel_baton));
 
637
 
 
638
  /* Save the result for reuse. */
 
639
  matches_changelists = ((changelists == NULL)
 
640
                         || (status->changelist != NULL
 
641
                             && svn_hash_gets(changelists, status->changelist)
 
642
                                != NULL));
 
643
 
 
644
  /* Early exit. */
 
645
  if (status->kind != svn_node_dir && ! matches_changelists)
 
646
    {
 
647
      return SVN_NO_ERROR;
 
648
    }
 
649
 
 
650
  /* If NODE is in our changelist, then examine it for conflicts. We
 
651
     need to bail out if any conflicts exist.
 
652
     The status walker checked for conflict marker removal. */
 
653
  if (status->conflicted && matches_changelists)
 
654
    {
 
655
      if (notify_func != NULL)
 
656
        {
 
657
          notify_func(notify_baton,
 
658
                      svn_wc_create_notify(local_abspath,
 
659
                                           svn_wc_notify_failed_conflict,
 
660
                                           scratch_pool),
 
661
                      scratch_pool);
 
662
        }
 
663
 
 
664
      return svn_error_createf(
 
665
            SVN_ERR_WC_FOUND_CONFLICT, NULL,
 
666
            _("Aborting commit: '%s' remains in conflict"),
 
667
            svn_dirent_local_style(local_abspath, scratch_pool));
 
668
    }
 
669
  else if (status->node_status == svn_wc_status_obstructed)
 
670
    {
 
671
      /* A node's type has changed before attempting to commit.
 
672
         This also catches symlink vs non symlink changes */
 
673
 
 
674
      if (notify_func != NULL)
 
675
        {
 
676
          notify_func(notify_baton,
 
677
                      svn_wc_create_notify(local_abspath,
 
678
                                           svn_wc_notify_failed_obstruction,
 
679
                                           scratch_pool),
 
680
                      scratch_pool);
 
681
        }
 
682
 
 
683
      return svn_error_createf(
 
684
                    SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
 
685
                    _("Node '%s' has unexpectedly changed kind"),
 
686
                    svn_dirent_local_style(local_abspath, scratch_pool));
 
687
    }
 
688
 
 
689
  if (status->conflicted && status->kind == svn_node_unknown)
 
690
    return SVN_NO_ERROR; /* Ignore delete-delete conflict */
484
691
 
485
692
  /* Return error on unknown path kinds.  We check both the entry and
486
693
     the node itself, since a path might have changed kind since its
487
694
     entry was written. */
488
 
  SVN_ERR(svn_wc__node_get_commit_status(&db_kind, &is_added, &is_deleted,
 
695
  SVN_ERR(svn_wc__node_get_commit_status(&is_added, &is_deleted,
489
696
                                         &is_replaced,
490
 
                                         &is_not_present, &is_excluded,
491
 
                                         &is_op_root, &is_symlink,
492
 
                                         &node_rev, &node_relpath,
 
697
                                         &is_op_root,
 
698
                                         &node_rev,
493
699
                                         &original_rev, &original_relpath,
494
 
                                         &conflicted,
495
 
                                         &node_changelist,
496
 
                                         &prop_mod, &is_update_root,
497
 
                                         &node_lock_token,
498
700
                                         wc_ctx, local_abspath,
499
701
                                         scratch_pool, scratch_pool));
500
702
 
501
 
  if ((skip_files && db_kind == svn_node_file) || is_excluded)
502
 
    return SVN_NO_ERROR;
503
 
 
504
 
  if (!node_relpath && commit_relpath)
505
 
    node_relpath = commit_relpath;
506
 
 
507
 
  SVN_ERR(svn_io_check_special_path(local_abspath, &working_kind, &is_special,
508
 
                                    scratch_pool));
509
 
 
510
 
  /* ### In 1.6 an obstructed dir would fail when locking before we
511
 
         got here.  Locking now doesn't fail so perhaps we should do
512
 
         some sort of checking here. */
513
 
 
514
 
  if ((working_kind != svn_node_file)
515
 
      && (working_kind != svn_node_dir)
516
 
      && (working_kind != svn_node_none))
517
 
    {
518
 
      return svn_error_createf
519
 
        (SVN_ERR_NODE_UNKNOWN_KIND, NULL,
520
 
         _("Unknown entry kind for '%s'"),
521
 
         svn_dirent_local_style(local_abspath, scratch_pool));
522
 
    }
523
 
 
524
 
  /* Save the result for reuse. */
525
 
  matches_changelists = ((changelists == NULL)
526
 
                         || (node_changelist != NULL
527
 
                             && apr_hash_get(changelists, node_changelist,
528
 
                                             APR_HASH_KEY_STRING) != NULL));
529
 
 
530
 
  /* Early exit. */
531
 
  if (working_kind != svn_node_dir && working_kind != svn_node_none
532
 
      && ! matches_changelists)
 
703
  /* Hande file externals only when passed as explicit target. Note that
 
704
   * svn_client_commit6() passes all committable externals in as explicit
 
705
   * targets iff they count. */
 
706
  if (status->file_external && !is_harvest_root)
533
707
    {
534
708
      return SVN_NO_ERROR;
535
709
    }
536
710
 
537
 
  /* Verify that the node's type has not changed before attempting to
538
 
     commit. */
539
 
  if ((((!is_symlink) && (is_special))
540
 
#ifdef HAVE_SYMLINK
541
 
       || (is_symlink && (! is_special))
542
 
#endif /* HAVE_SYMLINK */
543
 
       ) && (working_kind != svn_node_none))
544
 
    {
545
 
      return svn_error_createf
546
 
        (SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
547
 
         _("Entry '%s' has unexpectedly changed special status"),
548
 
         svn_dirent_local_style(local_abspath, scratch_pool));
549
 
    }
550
 
 
551
 
  if (copy_mode
552
 
      && is_update_root
553
 
      && db_kind == svn_node_file)
554
 
    {
555
 
      if (copy_mode)
556
 
        return SVN_NO_ERROR;
557
 
    }
558
 
 
559
 
  /* If NODE is in our changelist, then examine it for conflicts. We
560
 
     need to bail out if any conflicts exist.  */
561
 
  if (conflicted && matches_changelists)
562
 
    {
563
 
      svn_boolean_t tc, pc, treec;
564
 
 
565
 
      SVN_ERR(svn_wc_conflicted_p3(&tc, &pc, &treec, wc_ctx,
566
 
                                   local_abspath, scratch_pool));
567
 
      if (tc || pc || treec)
 
711
  if (status->node_status == svn_wc_status_missing && matches_changelists)
 
712
    {
 
713
      /* Added files and directories must exist. See issue #3198. */
 
714
      if (is_added && is_op_root)
568
715
        {
569
716
          if (notify_func != NULL)
570
717
            {
571
718
              notify_func(notify_baton,
572
719
                          svn_wc_create_notify(local_abspath,
573
 
                                               svn_wc_notify_failed_conflict,
 
720
                                               svn_wc_notify_failed_missing,
574
721
                                               scratch_pool),
575
722
                          scratch_pool);
576
723
            }
577
 
 
578
724
          return svn_error_createf(
579
 
            SVN_ERR_WC_FOUND_CONFLICT, NULL,
580
 
            _("Aborting commit: '%s' remains in conflict"),
581
 
            svn_dirent_local_style(local_abspath, scratch_pool));
 
725
             SVN_ERR_WC_PATH_NOT_FOUND, NULL,
 
726
             _("'%s' is scheduled for addition, but is missing"),
 
727
             svn_dirent_local_style(local_abspath, scratch_pool));
582
728
        }
 
729
 
 
730
      return SVN_NO_ERROR;
583
731
    }
584
732
 
585
733
  if (is_deleted && !is_op_root /* && !is_added */)
586
734
    return SVN_NO_ERROR; /* Not an operational delete and not an add. */
587
735
 
588
 
  if (node_relpath == NULL)
589
 
    SVN_ERR(svn_wc__node_get_repos_relpath(&node_relpath,
590
 
                                           wc_ctx, local_abspath,
591
 
                                           scratch_pool, scratch_pool));
592
736
  /* Check for the deletion case.
593
737
     * We delete explicitly deleted nodes (duh!)
594
738
     * We delete not-present children of copies
597
741
 
598
742
  if (is_deleted || is_replaced)
599
743
    state_flags |= SVN_CLIENT_COMMIT_ITEM_DELETE;
600
 
  else if (is_not_present)
601
 
    {
602
 
      if (! copy_mode)
603
 
        return SVN_NO_ERROR;
604
 
 
605
 
      /* We should check if we should really add a delete operation */
606
 
      if (check_url_func)
607
 
        {
608
 
          svn_revnum_t revision;
609
 
          const char *repos_relpath;
610
 
          svn_node_kind_t kind;
611
 
 
612
 
          /* Determine from what parent we would be the deleted child */
613
 
          SVN_ERR(svn_wc__node_get_origin(NULL, &revision, &repos_relpath,
614
 
                                          NULL, NULL, NULL, wc_ctx,
615
 
                                          svn_dirent_dirname(local_abspath,
616
 
                                                             scratch_pool),
617
 
                                          FALSE, scratch_pool, scratch_pool));
618
 
 
619
 
          repos_relpath = svn_relpath_join(repos_relpath,
620
 
                                           svn_dirent_basename(local_abspath,
621
 
                                                               NULL),
622
 
                                           scratch_pool);
623
 
 
624
 
          SVN_ERR(check_url_func(check_url_baton, &kind,
625
 
                                 svn_path_url_add_component2(repos_root_url,
626
 
                                                             repos_relpath,
627
 
                                                             scratch_pool),
628
 
                                 revision, scratch_pool));
629
 
 
630
 
          if (kind == svn_node_none)
631
 
            return SVN_NO_ERROR; /* This node can't be deleted */
632
 
        }
633
 
 
634
 
      state_flags |= SVN_CLIENT_COMMIT_ITEM_DELETE;
635
 
    }
636
744
 
637
745
  /* Check for adds and copies */
638
746
  if (is_added && is_op_root)
646
754
          state_flags |= SVN_CLIENT_COMMIT_ITEM_IS_COPY;
647
755
          cf_relpath = original_relpath;
648
756
          cf_rev = original_rev;
 
757
 
 
758
          if (status->moved_from_abspath && !copy_mode)
 
759
            {
 
760
              state_flags |= SVN_CLIENT_COMMIT_ITEM_MOVED_HERE;
 
761
              moved_from_abspath = status->moved_from_abspath;
 
762
            }
649
763
        }
650
764
    }
651
765
 
652
 
  /* Further additions occur in copy mode. */
653
 
  if (copy_mode
654
 
      && (!is_added || copy_mode_root)
655
 
      && !(state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE))
 
766
  /* Further copies may occur in copy mode. */
 
767
  else if (copy_mode
 
768
           && !(state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE))
656
769
    {
657
 
      svn_revnum_t dir_rev;
658
 
 
659
 
      if (!copy_mode_root)
660
 
        SVN_ERR(svn_wc__node_get_base_rev(&dir_rev, wc_ctx,
661
 
                                          svn_dirent_dirname(local_abspath,
662
 
                                                             scratch_pool),
663
 
                                          scratch_pool));
664
 
 
665
 
      if (copy_mode_root || node_rev != dir_rev)
666
 
        {
667
 
          state_flags |= SVN_CLIENT_COMMIT_ITEM_ADD;
668
 
 
669
 
          SVN_ERR(svn_wc__node_get_origin(NULL, &cf_rev,
670
 
                                      &cf_relpath, NULL,
671
 
                                      NULL, NULL,
672
 
                                      wc_ctx, local_abspath, FALSE,
 
770
      svn_revnum_t dir_rev = SVN_INVALID_REVNUM;
 
771
 
 
772
      if (!copy_mode_root && !status->switched && !is_added)
 
773
        SVN_ERR(svn_wc__node_get_base(NULL, &dir_rev, NULL, NULL, NULL, NULL,
 
774
                                      wc_ctx, svn_dirent_dirname(local_abspath,
 
775
                                                                 scratch_pool),
 
776
                                      FALSE /* ignore_enoent */,
 
777
                                      FALSE /* show_hidden */,
673
778
                                      scratch_pool, scratch_pool));
674
779
 
675
 
          if (cf_relpath)
676
 
            state_flags |= SVN_CLIENT_COMMIT_ITEM_IS_COPY;
677
 
        }
678
 
    }
679
 
 
680
 
  /* If an add is scheduled to occur, dig around for some more
681
 
     information about it. */
682
 
  if (state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)
683
 
    {
684
 
      /* First of all, the working file or directory must exist.
685
 
         See issue #3198. */
686
 
      if (working_kind == svn_node_none)
687
 
        {
688
 
          if (notify_func != NULL)
689
 
            {
690
 
              notify_func(notify_baton,
691
 
                          svn_wc_create_notify(local_abspath,
692
 
                                               svn_wc_notify_failed_missing,
693
 
                                               scratch_pool),
694
 
                          scratch_pool);
695
 
            }
696
 
          return svn_error_createf(
697
 
             SVN_ERR_WC_PATH_NOT_FOUND, NULL,
698
 
             _("'%s' is scheduled for addition, but is missing"),
699
 
             svn_dirent_local_style(local_abspath, scratch_pool));
700
 
        }
701
 
 
702
 
      /* Regular adds of files have text mods, but for copies we have
703
 
         to test for textual mods.  Directories simply don't have text! */
704
 
      if (db_kind == svn_node_file)
705
 
        {
706
 
          /* Check for text mods.  */
707
 
          if (state_flags & SVN_CLIENT_COMMIT_ITEM_IS_COPY)
708
 
            SVN_ERR(svn_wc_text_modified_p2(&text_mod, wc_ctx, local_abspath,
709
 
                                            FALSE, scratch_pool));
710
 
          else
711
 
            text_mod = TRUE;
712
 
        }
713
 
    }
714
 
 
715
 
  /* Else, if we aren't deleting this item, we'll have to look for
716
 
     local text or property mods to determine if the path might be
717
 
     committable. */
718
 
  else if (! (state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE))
719
 
    {
720
 
      /* Check for text mods on files.  If EOL_PROP_CHANGED is TRUE,
721
 
         then we need to force a translated byte-for-byte comparison
722
 
         against the text-base so that a timestamp comparison won't
723
 
         bail out early.  Depending on how the svn:eol-style prop was
724
 
         changed, we might have to send new text to the server to
725
 
         match the new newline style.  */
726
 
      if (db_kind == svn_node_file)
727
 
        SVN_ERR(svn_wc_text_modified_p2(&text_mod, wc_ctx, local_abspath,
728
 
                                        FALSE, scratch_pool));
729
 
    }
730
 
 
731
 
  /* Set text/prop modification flags accordingly. */
732
 
  if (text_mod)
733
 
    state_flags |= SVN_CLIENT_COMMIT_ITEM_TEXT_MODS;
734
 
  if (prop_mod)
735
 
    state_flags |= SVN_CLIENT_COMMIT_ITEM_PROP_MODS;
 
780
      if (copy_mode_root || status->switched || node_rev != dir_rev)
 
781
        {
 
782
          state_flags |= (SVN_CLIENT_COMMIT_ITEM_ADD
 
783
                          | SVN_CLIENT_COMMIT_ITEM_IS_COPY);
 
784
 
 
785
          if (status->copied)
 
786
            {
 
787
              /* Copy from original location */
 
788
              cf_rev = original_rev;
 
789
              cf_relpath = original_relpath;
 
790
            }
 
791
          else
 
792
            {
 
793
              /* Copy BASE location, to represent a mixed-rev or switch copy */
 
794
              cf_rev = status->revision;
 
795
              cf_relpath = status->repos_relpath;
 
796
            }
 
797
        }
 
798
    }
 
799
 
 
800
  if (!(state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
 
801
      || (state_flags & SVN_CLIENT_COMMIT_ITEM_ADD))
 
802
    {
 
803
      svn_boolean_t text_mod = FALSE;
 
804
      svn_boolean_t prop_mod = FALSE;
 
805
 
 
806
      if (status->kind == svn_node_file)
 
807
        {
 
808
          /* Check for text modifications on files */
 
809
          if ((state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)
 
810
              && ! (state_flags & SVN_CLIENT_COMMIT_ITEM_IS_COPY))
 
811
            {
 
812
              text_mod = TRUE; /* Local added files are always modified */
 
813
            }
 
814
          else
 
815
            text_mod = (status->text_status != svn_wc_status_normal);
 
816
        }
 
817
 
 
818
      prop_mod = (status->prop_status != svn_wc_status_normal
 
819
                  && status->prop_status != svn_wc_status_none);
 
820
 
 
821
      /* Set text/prop modification flags accordingly. */
 
822
      if (text_mod)
 
823
        state_flags |= SVN_CLIENT_COMMIT_ITEM_TEXT_MODS;
 
824
      if (prop_mod)
 
825
        state_flags |= SVN_CLIENT_COMMIT_ITEM_PROP_MODS;
 
826
    }
736
827
 
737
828
  /* If the entry has a lock token and it is already a commit candidate,
738
829
     or the caller wants unmodified locked items to be treated as
739
830
     such, note this fact. */
740
 
  if (node_lock_token && lock_tokens && (state_flags || just_locked))
 
831
  if (status->lock && baton->lock_tokens && (state_flags || just_locked))
741
832
    {
742
833
      state_flags |= SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN;
743
834
    }
744
835
 
745
836
  /* Now, if this is something to commit, add it to our list. */
746
 
  if (state_flags)
 
837
  if (matches_changelists
 
838
      && state_flags)
747
839
    {
748
 
      if (matches_changelists)
749
 
        {
750
 
          /* Finally, add the committable item. */
751
 
          SVN_ERR(add_committable(committables, local_abspath, db_kind,
752
 
                                  repos_root_url,
753
 
                                  copy_mode
 
840
      /* Finally, add the committable item. */
 
841
      SVN_ERR(add_committable(committables, local_abspath,
 
842
                              status->kind,
 
843
                              repos_root_url,
 
844
                              copy_mode
754
845
                                      ? commit_relpath
755
 
                                      : node_relpath,
756
 
                                  copy_mode
 
846
                                      : status->repos_relpath,
 
847
                              copy_mode
757
848
                                      ? SVN_INVALID_REVNUM
758
849
                                      : node_rev,
759
 
                                  cf_relpath,
760
 
                                  cf_rev,
761
 
                                  state_flags,
762
 
                                  result_pool, scratch_pool));
763
 
          if (state_flags & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN)
764
 
            apr_hash_set(lock_tokens,
765
 
                         svn_path_url_add_component2(
766
 
                             repos_root_url, node_relpath,
767
 
                             apr_hash_pool_get(lock_tokens)),
768
 
                         APR_HASH_KEY_STRING,
769
 
                         apr_pstrdup(apr_hash_pool_get(lock_tokens),
770
 
                                     node_lock_token));
771
 
        }
 
850
                              cf_relpath,
 
851
                              cf_rev,
 
852
                              moved_from_abspath,
 
853
                              state_flags,
 
854
                              baton->lock_tokens, status->lock,
 
855
                              result_pool, scratch_pool));
772
856
    }
773
857
 
774
 
    /* Fetch lock tokens for descendants of deleted nodes. */
775
 
  if (lock_tokens
776
 
      && (state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE))
 
858
    /* Fetch lock tokens for descendants of deleted BASE nodes. */
 
859
  if (matches_changelists
 
860
      && (state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
 
861
      && !copy_mode
 
862
      && SVN_IS_VALID_REVNUM(node_rev) /* && BASE-kind = dir */
 
863
      && baton->lock_tokens)
777
864
    {
778
865
      apr_hash_t *local_relpath_tokens;
779
866
      apr_hash_index_t *hi;
780
 
      apr_pool_t *token_pool = apr_hash_pool_get(lock_tokens);
781
867
 
782
868
      SVN_ERR(svn_wc__node_get_lock_tokens_recursive(
783
869
                  &local_relpath_tokens, wc_ctx, local_abspath,
784
 
                  token_pool, scratch_pool));
 
870
                  result_pool, scratch_pool));
785
871
 
786
872
      /* Add tokens to existing hash. */
787
873
      for (hi = apr_hash_first(scratch_pool, local_relpath_tokens);
794
880
 
795
881
          apr_hash_this(hi, &key, &klen, &val);
796
882
 
797
 
          apr_hash_set(lock_tokens, key, klen, val);
 
883
          apr_hash_set(baton->lock_tokens, key, klen, val);
798
884
        }
799
885
    }
800
886
 
801
 
  /* Make sure we check for dangling children on additions */
802
 
  if (state_flags && is_added && danglers)
 
887
  /* Make sure we check for dangling children on additions
 
888
 
 
889
     We perform this operation on the harvest root, and on roots caused by
 
890
     changelist filtering.
 
891
  */
 
892
  if (matches_changelists
 
893
      && (is_harvest_root || baton->changelists)
 
894
      && state_flags
 
895
      && is_added
 
896
      && baton->danglers)
803
897
    {
804
 
      /* If a node is added, it's parent must exist in the repository at the
 
898
      /* If a node is added, its parent must exist in the repository at the
805
899
         time of committing */
806
 
 
 
900
      apr_hash_t *danglers = baton->danglers;
807
901
      svn_boolean_t parent_added;
808
902
      const char *parent_abspath = svn_dirent_dirname(local_abspath,
809
903
                                                      scratch_pool);
810
904
 
811
 
      SVN_ERR(svn_wc__node_is_added(&parent_added, wc_ctx, parent_abspath,
812
 
                                    scratch_pool));
 
905
      /* First check if parent is already in the list of commits
 
906
         (Common case for GUI clients that provide a list of commit targets) */
 
907
      if (look_up_committable(committables, parent_abspath, scratch_pool))
 
908
        parent_added = FALSE; /* Skip all expensive checks */
 
909
      else
 
910
        SVN_ERR(svn_wc__node_is_added(&parent_added, wc_ctx, parent_abspath,
 
911
                                      scratch_pool));
813
912
 
814
913
      if (parent_added)
815
914
        {
827
926
          if (parent_is_copy)
828
927
            parent_abspath = copy_root_abspath;
829
928
 
830
 
          if (!apr_hash_get(danglers, parent_abspath, APR_HASH_KEY_STRING))
 
929
          if (!svn_hash_gets(danglers, parent_abspath))
831
930
            {
832
 
              apr_hash_set(danglers,
833
 
                           apr_pstrdup(result_pool, parent_abspath),
834
 
                           APR_HASH_KEY_STRING,
835
 
                           apr_pstrdup(result_pool, local_abspath));
 
931
              svn_hash_sets(danglers, apr_pstrdup(result_pool, parent_abspath),
 
932
                            apr_pstrdup(result_pool, local_abspath));
836
933
            }
837
934
        }
838
935
    }
839
936
 
840
 
  if (db_kind != svn_node_dir || depth <= svn_depth_empty)
841
 
    return SVN_NO_ERROR;
842
 
 
843
 
  SVN_ERR(bail_on_tree_conflicted_children(wc_ctx, local_abspath,
844
 
                                           db_kind, depth, changelists,
845
 
                                           notify_func, notify_baton,
846
 
                                           scratch_pool));
 
937
  if (is_deleted && !is_added)
 
938
    {
 
939
      /* Skip all descendants */
 
940
      if (status->kind == svn_node_dir)
 
941
        baton->skip_below_abspath = apr_pstrdup(baton->result_pool,
 
942
                                                local_abspath);
 
943
      return SVN_NO_ERROR;
 
944
    }
847
945
 
848
946
  /* Recursively handle each node according to depth, except when the
849
 
     node is only being deleted. */
850
 
  if ((! (state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE))
851
 
      || (state_flags & SVN_CLIENT_COMMIT_ITEM_ADD))
 
947
     node is only being deleted, or is in an added tree (as added trees
 
948
     use the normal commit handling). */
 
949
  if (copy_mode && !is_added && !is_deleted && status->kind == svn_node_dir)
852
950
    {
853
 
      const apr_array_header_t *children;
854
 
      apr_pool_t *iterpool = svn_pool_create(scratch_pool);
855
 
      int i;
856
 
      svn_depth_t depth_below_here = depth;
857
 
 
858
 
      if (depth < svn_depth_infinity)
859
 
        depth_below_here = svn_depth_empty; /* Stop recursing */
860
 
 
861
 
      SVN_ERR(svn_wc__node_get_children_of_working_node(
862
 
                &children, wc_ctx, local_abspath, copy_mode,
863
 
                scratch_pool, iterpool));
864
 
      for (i = 0; i < children->nelts; i++)
865
 
        {
866
 
          const char *this_abspath = APR_ARRAY_IDX(children, i, const char *);
867
 
          const char *name = svn_dirent_basename(this_abspath, NULL);
868
 
          const char *this_commit_relpath;
869
 
 
870
 
          svn_pool_clear(iterpool);
871
 
 
872
 
          if (commit_relpath == NULL)
873
 
            this_commit_relpath = NULL;
874
 
          else
875
 
            this_commit_relpath = svn_relpath_join(commit_relpath, name,
876
 
                                                   iterpool);
877
 
 
878
 
          SVN_ERR(harvest_committables(wc_ctx, this_abspath,
879
 
                                       committables, lock_tokens,
880
 
                                       repos_root_url,
881
 
                                       this_commit_relpath,
882
 
                                       FALSE, /* COPY_MODE_ROOT */
883
 
                                       depth_below_here,
884
 
                                       just_locked,
885
 
                                       changelists,
886
 
                                       (depth < svn_depth_files),
887
 
                                       (depth < svn_depth_immediates),
888
 
                                       NULL, /* danglers */
889
 
                                       check_url_func, check_url_baton,
890
 
                                       cancel_func, cancel_baton,
891
 
                                       notify_func, notify_baton,
892
 
                                       result_pool,
893
 
                                       iterpool));
894
 
        }
895
 
 
896
 
      svn_pool_destroy(iterpool);
 
951
      SVN_ERR(harvest_not_present_for_copy(wc_ctx, local_abspath, committables,
 
952
                                           repos_root_url, commit_relpath,
 
953
                                           baton->check_url_func,
 
954
                                           baton->check_url_baton,
 
955
                                           result_pool, scratch_pool));
897
956
    }
898
957
 
899
958
  return SVN_NO_ERROR;
1029
1088
                                 apr_hash_t **lock_tokens,
1030
1089
                                 const char *base_dir_abspath,
1031
1090
                                 const apr_array_header_t *targets,
 
1091
                                 int depth_empty_start,
1032
1092
                                 svn_depth_t depth,
1033
1093
                                 svn_boolean_t just_locked,
1034
1094
                                 const apr_array_header_t *changelists,
1041
1101
  int i;
1042
1102
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
1043
1103
  apr_hash_t *changelist_hash = NULL;
1044
 
  svn_wc_context_t *wc_ctx = ctx->wc_ctx;
1045
1104
  struct handle_descendants_baton hdb;
1046
1105
  apr_hash_index_t *hi;
1047
1106
 
1086
1145
  for (i = 0; i < targets->nelts; ++i)
1087
1146
    {
1088
1147
      const char *target_abspath;
1089
 
      svn_node_kind_t kind;
1090
 
      const char *repos_root_url;
1091
1148
 
1092
1149
      svn_pool_clear(iterpool);
1093
1150
 
1096
1153
                                       APR_ARRAY_IDX(targets, i, const char *),
1097
1154
                                       iterpool);
1098
1155
 
1099
 
      SVN_ERR(svn_wc_read_kind(&kind, wc_ctx, target_abspath,
1100
 
                               FALSE, /* show_hidden */
1101
 
                               iterpool));
1102
 
      if (kind == svn_node_none)
1103
 
        {
1104
 
          /* If a target of the commit is a tree-conflicted node that
1105
 
           * has no entry (e.g. locally deleted), issue a proper tree-
1106
 
           * conflicts error instead of a "not under version control". */
1107
 
          const svn_wc_conflict_description2_t *conflict;
1108
 
          SVN_ERR(svn_wc__get_tree_conflict(&conflict, wc_ctx, target_abspath,
1109
 
                                            iterpool, iterpool));
1110
 
          if (conflict != NULL)
1111
 
            return svn_error_createf(
1112
 
                       SVN_ERR_WC_FOUND_CONFLICT, NULL,
1113
 
                       _("Aborting commit: '%s' remains in conflict"),
1114
 
                       svn_dirent_local_style(conflict->local_abspath,
1115
 
                                              iterpool));
1116
 
          else
1117
 
            return svn_error_createf(
1118
 
                       SVN_ERR_ILLEGAL_TARGET, NULL,
1119
 
                       _("'%s' is not under version control"),
1120
 
                       svn_dirent_local_style(target_abspath, iterpool));
1121
 
        }
1122
 
 
1123
 
      SVN_ERR(svn_wc__node_get_repos_info(&repos_root_url, NULL, wc_ctx,
1124
 
                                          target_abspath,
1125
 
                                          result_pool, iterpool));
1126
 
 
1127
1156
      /* Handle our TARGET. */
1128
1157
      /* Make sure this isn't inside a working copy subtree that is
1129
1158
       * marked as tree-conflicted. */
1132
1161
                                               ctx->notify_baton2,
1133
1162
                                               iterpool));
1134
1163
 
1135
 
      SVN_ERR(harvest_committables(ctx->wc_ctx, target_abspath,
 
1164
      /* Are the remaining items externals with depth empty? */
 
1165
      if (i == depth_empty_start)
 
1166
        depth = svn_depth_empty;
 
1167
 
 
1168
      SVN_ERR(harvest_committables(target_abspath,
1136
1169
                                   *committables, *lock_tokens,
1137
 
                                   repos_root_url,
1138
 
                                   NULL /* COMMIT_RELPATH */,
1139
 
                                   FALSE /* COPY_MODE_ROOT */,
 
1170
                                   NULL /* COPY_MODE_RELPATH */,
1140
1171
                                   depth, just_locked, changelist_hash,
1141
 
                                   FALSE, FALSE,
1142
1172
                                   danglers,
1143
1173
                                   check_url_func, check_url_baton,
1144
1174
                                   ctx->cancel_func, ctx->cancel_baton,
1145
1175
                                   ctx->notify_func2, ctx->notify_baton2,
1146
 
                                   result_pool, iterpool));
 
1176
                                   ctx->wc_ctx, result_pool, iterpool));
1147
1177
    }
1148
1178
 
1149
1179
  hdb.wc_ctx = ctx->wc_ctx;
1215
1245
  /* Read the entry for this SRC. */
1216
1246
  SVN_ERR_ASSERT(svn_dirent_is_absolute(pair->src_abspath_or_url));
1217
1247
 
1218
 
  SVN_ERR(svn_wc__node_get_repos_info(&repos_root_url, NULL, btn->ctx->wc_ctx,
 
1248
  SVN_ERR(svn_wc__node_get_repos_info(NULL, NULL, &repos_root_url, NULL,
 
1249
                                      btn->ctx->wc_ctx,
1219
1250
                                      pair->src_abspath_or_url,
1220
1251
                                      pool, pool));
1221
1252
 
1223
1254
                                         pair->dst_abspath_or_url, pool);
1224
1255
 
1225
1256
  /* Handle this SRC. */
1226
 
  SVN_ERR(harvest_committables(btn->ctx->wc_ctx,
1227
 
                               pair->src_abspath_or_url,
 
1257
  SVN_ERR(harvest_committables(pair->src_abspath_or_url,
1228
1258
                               btn->committables, NULL,
1229
 
                               repos_root_url,
1230
1259
                               commit_relpath,
1231
 
                               TRUE,  /* COPY_MODE_ROOT */
1232
1260
                               svn_depth_infinity,
1233
1261
                               FALSE,  /* JUST_LOCKED */
1234
 
                               NULL,
1235
 
                               FALSE, FALSE, /* skip files, dirs */
 
1262
                               NULL /* changelists */,
1236
1263
                               NULL,
1237
1264
                               btn->check_url_func,
1238
1265
                               btn->check_url_baton,
1240
1267
                               btn->ctx->cancel_baton,
1241
1268
                               btn->ctx->notify_func2,
1242
1269
                               btn->ctx->notify_baton2,
1243
 
                               btn->result_pool, pool));
 
1270
                               btn->ctx->wc_ctx, btn->result_pool, pool));
1244
1271
 
1245
1272
  hdb.wc_ctx = btn->ctx->wc_ctx;
1246
1273
  hdb.cancel_func = btn->ctx->cancel_func;
1357
1384
    {
1358
1385
      svn_client_commit_item3_t *this_item
1359
1386
        = APR_ARRAY_IDX(ci, i, svn_client_commit_item3_t *);
1360
 
      size_t url_len = strlen(this_item->url);
1361
 
      size_t base_url_len = strlen(*base_url);
1362
1387
 
1363
 
      if (url_len > base_url_len)
1364
 
        this_item->session_relpath = svn_uri__is_child(*base_url,
1365
 
                                                       this_item->url, pool);
1366
 
      else
1367
 
        this_item->session_relpath = "";
 
1388
      this_item->session_relpath = svn_uri_skip_ancestor(*base_url,
 
1389
                                                         this_item->url, pool);
1368
1390
    }
1369
1391
#ifdef SVN_CLIENT_COMMIT_DEBUG
1370
1392
  /* ### TEMPORARY CODE ### */
1437
1459
               apr_pool_t *pool)
1438
1460
{
1439
1461
  struct item_commit_baton *icb = callback_baton;
1440
 
  const svn_client_commit_item3_t *item = apr_hash_get(icb->commit_items,
1441
 
                                                       path,
1442
 
                                                       APR_HASH_KEY_STRING);
 
1462
  const svn_client_commit_item3_t *item = svn_hash_gets(icb->commit_items,
 
1463
                                                        path);
1443
1464
  svn_node_kind_t kind = item->kind;
1444
1465
  void *file_baton = NULL;
1445
1466
  apr_pool_t *file_pool = NULL;
1567
1588
                                 parent_baton, pool);
1568
1589
 
1569
1590
      if (err)
1570
 
        return svn_error_trace(fixup_commit_error(local_abspath,
1571
 
                                                  icb->base_url,
1572
 
                                                  path, item->kind,
1573
 
                                                  err, ctx, pool));
 
1591
        goto fixup_error;
1574
1592
    }
1575
1593
 
1576
1594
  /* If this item is supposed to be added, do so. */
1594
1612
        }
1595
1613
 
1596
1614
      if (err)
1597
 
        return svn_error_trace(fixup_commit_error(local_abspath,
1598
 
                                                  icb->base_url,
1599
 
                                                  path, kind, err,
1600
 
                                                  ctx, pool));
 
1615
        goto fixup_error;
1601
1616
 
1602
1617
      /* Set other prop-changes, if available in the baton */
1603
1618
      if (item->outgoing_prop_changes)
1610
1625
              prop = APR_ARRAY_IDX(prop_changes, ctr, svn_prop_t *);
1611
1626
              if (kind == svn_node_file)
1612
1627
                {
1613
 
                  editor->change_file_prop(file_baton, prop->name,
1614
 
                                           prop->value, pool);
 
1628
                  err = editor->change_file_prop(file_baton, prop->name,
 
1629
                                                 prop->value, pool);
1615
1630
                }
1616
1631
              else
1617
1632
                {
1618
 
                  editor->change_dir_prop(*dir_baton, prop->name,
1619
 
                                          prop->value, pool);
 
1633
                  err = editor->change_dir_prop(*dir_baton, prop->name,
 
1634
                                                prop->value, pool);
1620
1635
                }
 
1636
 
 
1637
              if (err)
 
1638
                goto fixup_error;
1621
1639
            }
1622
1640
        }
1623
1641
    }
1635
1653
                                      file_pool, &file_baton);
1636
1654
 
1637
1655
              if (err)
1638
 
                return svn_error_trace(fixup_commit_error(local_abspath,
1639
 
                                                          icb->base_url,
1640
 
                                                          path, kind,
1641
 
                                                          err, ctx,
1642
 
                                                          pool));
 
1656
                goto fixup_error;
1643
1657
            }
1644
1658
        }
1645
1659
      else
1659
1673
                }
1660
1674
 
1661
1675
              if (err)
1662
 
                return svn_error_trace(fixup_commit_error(local_abspath,
1663
 
                                                          icb->base_url,
1664
 
                                                          path, kind,
1665
 
                                                          err, ctx,
1666
 
                                                          pool));
 
1676
                goto fixup_error;
1667
1677
            }
1668
1678
        }
1669
1679
 
1676
1686
              (kind == svn_node_dir) ? *dir_baton : file_baton, pool);
1677
1687
 
1678
1688
      if (err)
1679
 
        return svn_error_trace(fixup_commit_error(local_abspath,
1680
 
                                                  icb->base_url,
1681
 
                                                  path, kind, err,
1682
 
                                                  ctx, pool));
 
1689
        goto fixup_error;
1683
1690
 
1684
1691
      /* Make any additional client -> repository prop changes. */
1685
1692
      if (item->outgoing_prop_changes)
1693
1700
                                   svn_prop_t *);
1694
1701
              if (kind == svn_node_file)
1695
1702
                {
1696
 
                  editor->change_file_prop(file_baton, prop->name,
 
1703
                  err = editor->change_file_prop(file_baton, prop->name,
1697
1704
                                           prop->value, pool);
1698
1705
                }
1699
1706
              else
1700
1707
                {
1701
 
                  editor->change_dir_prop(*dir_baton, prop->name,
 
1708
                  err = editor->change_dir_prop(*dir_baton, prop->name,
1702
1709
                                          prop->value, pool);
1703
1710
                }
 
1711
 
 
1712
              if (err)
 
1713
                goto fixup_error;
1704
1714
            }
1705
1715
        }
1706
1716
    }
1721
1731
                                    file_pool, &file_baton);
1722
1732
 
1723
1733
          if (err)
1724
 
            return svn_error_trace(fixup_commit_error(local_abspath,
1725
 
                                                      icb->base_url,
1726
 
                                                      path, kind,
1727
 
                                                      err, ctx, pool));
 
1734
            goto fixup_error;
1728
1735
        }
1729
1736
 
1730
1737
      /* Add this file mod to the FILE_MODS hash. */
1731
1738
      mod->item = item;
1732
1739
      mod->file_baton = file_baton;
1733
 
      apr_hash_set(file_mods, item->session_relpath, APR_HASH_KEY_STRING, mod);
 
1740
      svn_hash_sets(file_mods, item->session_relpath, mod);
1734
1741
    }
1735
1742
  else if (file_baton)
1736
1743
    {
1739
1746
      err = editor->close_file(file_baton, NULL, file_pool);
1740
1747
 
1741
1748
      if (err)
1742
 
        return svn_error_trace(fixup_commit_error(local_abspath,
1743
 
                                                  icb->base_url,
1744
 
                                                  path, kind,
1745
 
                                                  err, ctx, pool));
 
1749
        goto fixup_error;
1746
1750
    }
1747
1751
 
1748
1752
  return SVN_NO_ERROR;
 
1753
 
 
1754
fixup_error:
 
1755
  return svn_error_trace(fixup_commit_error(local_abspath,
 
1756
                                            icb->base_url,
 
1757
                                            path, kind,
 
1758
                                            err, ctx, pool));
1749
1759
}
1750
1760
 
1751
 
 
1752
 
#ifdef SVN_CLIENT_COMMIT_DEBUG
1753
 
/* Prototype for function below */
1754
 
static svn_error_t *get_test_editor(const svn_delta_editor_t **editor,
1755
 
                                    void **edit_baton,
1756
 
                                    const svn_delta_editor_t *real_editor,
1757
 
                                    void *real_eb,
1758
 
                                    const char *base_url,
1759
 
                                    apr_pool_t *pool);
1760
 
#endif /* SVN_CLIENT_COMMIT_DEBUG */
1761
 
 
1762
1761
svn_error_t *
1763
1762
svn_client__do_commit(const char *base_url,
1764
1763
                      const apr_array_header_t *commit_items,
1765
1764
                      const svn_delta_editor_t *editor,
1766
1765
                      void *edit_baton,
1767
1766
                      const char *notify_path_prefix,
1768
 
                      apr_hash_t **md5_checksums,
1769
1767
                      apr_hash_t **sha1_checksums,
1770
1768
                      svn_client_ctx_t *ctx,
1771
1769
                      apr_pool_t *result_pool,
1780
1778
  apr_array_header_t *paths =
1781
1779
    apr_array_make(scratch_pool, commit_items->nelts, sizeof(const char *));
1782
1780
 
1783
 
#ifdef SVN_CLIENT_COMMIT_DEBUG
1784
 
  {
1785
 
    SVN_ERR(get_test_editor(&editor, &edit_baton,
1786
 
                            editor, edit_baton,
1787
 
                            base_url, scratch_pool));
1788
 
  }
1789
 
#endif /* SVN_CLIENT_COMMIT_DEBUG */
1790
 
 
1791
1781
  /* Ditto for the checksums. */
1792
 
  if (md5_checksums)
1793
 
    *md5_checksums = apr_hash_make(result_pool);
1794
1782
  if (sha1_checksums)
1795
1783
    *sha1_checksums = apr_hash_make(result_pool);
1796
1784
 
1802
1790
      svn_client_commit_item3_t *item =
1803
1791
        APR_ARRAY_IDX(commit_items, i, svn_client_commit_item3_t *);
1804
1792
      const char *path = item->session_relpath;
1805
 
      apr_hash_set(items_hash, path, APR_HASH_KEY_STRING, item);
 
1793
      svn_hash_sets(items_hash, path, item);
1806
1794
      APR_ARRAY_PUSH(paths, const char *) = path;
1807
1795
    }
1808
1796
 
1816
1804
  cb_baton.base_url = base_url;
1817
1805
 
1818
1806
  /* Drive the commit editor! */
1819
 
  SVN_ERR(svn_delta_path_driver(editor, edit_baton, SVN_INVALID_REVNUM,
1820
 
                                paths, do_item_commit, &cb_baton,
1821
 
                                scratch_pool));
 
1807
  SVN_ERR(svn_delta_path_driver2(editor, edit_baton, paths, TRUE,
 
1808
                                 do_item_commit, &cb_baton, scratch_pool));
1822
1809
 
1823
1810
  /* Transmit outstanding text deltas. */
1824
1811
  for (hi = apr_hash_first(scratch_pool, file_mods);
1870
1857
                                                    err, ctx, scratch_pool));
1871
1858
        }
1872
1859
 
1873
 
      if (md5_checksums)
1874
 
        apr_hash_set(*md5_checksums, item->path, APR_HASH_KEY_STRING,
1875
 
                     new_text_base_md5_checksum);
1876
1860
      if (sha1_checksums)
1877
 
        apr_hash_set(*sha1_checksums, item->path, APR_HASH_KEY_STRING,
1878
 
                     new_text_base_sha1_checksum);
 
1861
        svn_hash_sets(*sha1_checksums, item->path, new_text_base_sha1_checksum);
1879
1862
    }
1880
1863
 
1881
1864
  svn_pool_destroy(iterpool);
1885
1868
}
1886
1869
 
1887
1870
 
1888
 
#ifdef SVN_CLIENT_COMMIT_DEBUG
1889
 
 
1890
 
/*** Temporary test editor ***/
1891
 
 
1892
 
struct edit_baton
1893
 
{
1894
 
  const char *path;
1895
 
 
1896
 
  const svn_delta_editor_t *real_editor;
1897
 
  void *real_eb;
1898
 
};
1899
 
 
1900
 
struct item_baton
1901
 
{
1902
 
  struct edit_baton *eb;
1903
 
  void *real_baton;
1904
 
 
1905
 
  const char *path;
1906
 
};
1907
 
 
1908
 
static struct item_baton *
1909
 
make_baton(struct edit_baton *eb,
1910
 
           void *real_baton,
1911
 
           const char *path,
1912
 
           apr_pool_t *pool)
1913
 
{
1914
 
  struct item_baton *new_baton = apr_pcalloc(pool, sizeof(*new_baton));
1915
 
  new_baton->eb = eb;
1916
 
  new_baton->real_baton = real_baton;
1917
 
  new_baton->path = apr_pstrdup(pool, path);
1918
 
  return new_baton;
1919
 
}
1920
 
 
1921
 
static svn_error_t *
1922
 
set_target_revision(void *edit_baton,
1923
 
                    svn_revnum_t target_revision,
1924
 
                    apr_pool_t *pool)
1925
 
{
1926
 
  struct edit_baton *eb = edit_baton;
1927
 
  return (*eb->real_editor->set_target_revision)(eb->real_eb,
1928
 
                                                 target_revision,
1929
 
                                                 pool);
1930
 
}
1931
 
 
1932
 
static svn_error_t *
1933
 
open_root(void *edit_baton,
1934
 
          svn_revnum_t base_revision,
1935
 
          apr_pool_t *dir_pool,
1936
 
          void **root_baton)
1937
 
{
1938
 
  struct edit_baton *eb = edit_baton;
1939
 
  struct item_baton *new_baton = make_baton(eb, NULL, eb->path, dir_pool);
1940
 
  fprintf(stderr, "TEST EDIT STARTED (base URL=%s)\n", eb->path);
1941
 
  *root_baton = new_baton;
1942
 
  return (*eb->real_editor->open_root)(eb->real_eb,
1943
 
                                       base_revision,
1944
 
                                       dir_pool,
1945
 
                                       &new_baton->real_baton);
1946
 
}
1947
 
 
1948
 
static svn_error_t *
1949
 
add_file(const char *path,
1950
 
         void *parent_baton,
1951
 
         const char *copyfrom_path,
1952
 
         svn_revnum_t copyfrom_revision,
1953
 
         apr_pool_t *pool,
1954
 
         void **baton)
1955
 
{
1956
 
  struct item_baton *db = parent_baton;
1957
 
  struct item_baton *new_baton = make_baton(db->eb, NULL, path, pool);
1958
 
  const char *copystuffs = "";
1959
 
  if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_revision))
1960
 
    copystuffs = apr_psprintf(pool,
1961
 
                              " (copied from %s:%ld)",
1962
 
                              copyfrom_path,
1963
 
                              copyfrom_revision);
1964
 
  fprintf(stderr, "   Adding  : %s%s\n", path, copystuffs);
1965
 
  *baton = new_baton;
1966
 
  return (*db->eb->real_editor->add_file)(path, db->real_baton,
1967
 
                                          copyfrom_path, copyfrom_revision,
1968
 
                                          pool, &new_baton->real_baton);
1969
 
}
1970
 
 
1971
 
static svn_error_t *
1972
 
delete_entry(const char *path,
1973
 
             svn_revnum_t revision,
1974
 
             void *parent_baton,
1975
 
             apr_pool_t *pool)
1976
 
{
1977
 
  struct item_baton *db = parent_baton;
1978
 
  fprintf(stderr, "   Deleting: %s\n", path);
1979
 
  return (*db->eb->real_editor->delete_entry)(path, revision,
1980
 
                                              db->real_baton, pool);
1981
 
}
1982
 
 
1983
 
static svn_error_t *
1984
 
open_file(const char *path,
1985
 
          void *parent_baton,
1986
 
          svn_revnum_t base_revision,
1987
 
          apr_pool_t *pool,
1988
 
          void **baton)
1989
 
{
1990
 
  struct item_baton *db = parent_baton;
1991
 
  struct item_baton *new_baton = make_baton(db->eb, NULL, path, pool);
1992
 
  fprintf(stderr, "   Opening : %s\n", path);
1993
 
  *baton = new_baton;
1994
 
  return (*db->eb->real_editor->open_file)(path, db->real_baton,
1995
 
                                           base_revision, pool,
1996
 
                                           &new_baton->real_baton);
1997
 
}
1998
 
 
1999
 
static svn_error_t *
2000
 
close_file(void *baton, const char *text_checksum, apr_pool_t *pool)
2001
 
{
2002
 
  struct item_baton *fb = baton;
2003
 
  fprintf(stderr, "   Closing : %s\n", fb->path);
2004
 
  return (*fb->eb->real_editor->close_file)(fb->real_baton,
2005
 
                                            text_checksum, pool);
2006
 
}
2007
 
 
2008
 
 
2009
 
static svn_error_t *
2010
 
change_file_prop(void *file_baton,
2011
 
                 const char *name,
2012
 
                 const svn_string_t *value,
2013
 
                 apr_pool_t *pool)
2014
 
{
2015
 
  struct item_baton *fb = file_baton;
2016
 
  fprintf(stderr, "      PropSet (%s=%s)\n", name, value ? value->data : "");
2017
 
  return (*fb->eb->real_editor->change_file_prop)(fb->real_baton,
2018
 
                                                  name, value, pool);
2019
 
}
2020
 
 
2021
 
static svn_error_t *
2022
 
apply_textdelta(void *file_baton,
2023
 
                const char *base_checksum,
2024
 
                apr_pool_t *pool,
2025
 
                svn_txdelta_window_handler_t *handler,
2026
 
                void **handler_baton)
2027
 
{
2028
 
  struct item_baton *fb = file_baton;
2029
 
  fprintf(stderr, "      Transmitting text...\n");
2030
 
  return (*fb->eb->real_editor->apply_textdelta)(fb->real_baton,
2031
 
                                                 base_checksum, pool,
2032
 
                                                 handler, handler_baton);
2033
 
}
2034
 
 
2035
 
static svn_error_t *
2036
 
close_edit(void *edit_baton, apr_pool_t *pool)
2037
 
{
2038
 
  struct edit_baton *eb = edit_baton;
2039
 
  fprintf(stderr, "TEST EDIT COMPLETED\n");
2040
 
  return (*eb->real_editor->close_edit)(eb->real_eb, pool);
2041
 
}
2042
 
 
2043
 
static svn_error_t *
2044
 
add_directory(const char *path,
2045
 
              void *parent_baton,
2046
 
              const char *copyfrom_path,
2047
 
              svn_revnum_t copyfrom_revision,
2048
 
              apr_pool_t *pool,
2049
 
              void **baton)
2050
 
{
2051
 
  struct item_baton *db = parent_baton;
2052
 
  struct item_baton *new_baton = make_baton(db->eb, NULL, path, pool);
2053
 
  const char *copystuffs = "";
2054
 
  if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_revision))
2055
 
    copystuffs = apr_psprintf(pool,
2056
 
                              " (copied from %s:%ld)",
2057
 
                              copyfrom_path,
2058
 
                              copyfrom_revision);
2059
 
  fprintf(stderr, "   Adding  : %s%s\n", path, copystuffs);
2060
 
  *baton = new_baton;
2061
 
  return (*db->eb->real_editor->add_directory)(path,
2062
 
                                               db->real_baton,
2063
 
                                               copyfrom_path,
2064
 
                                               copyfrom_revision,
2065
 
                                               pool,
2066
 
                                               &new_baton->real_baton);
2067
 
}
2068
 
 
2069
 
static svn_error_t *
2070
 
open_directory(const char *path,
2071
 
               void *parent_baton,
2072
 
               svn_revnum_t base_revision,
2073
 
               apr_pool_t *pool,
2074
 
               void **baton)
2075
 
{
2076
 
  struct item_baton *db = parent_baton;
2077
 
  struct item_baton *new_baton = make_baton(db->eb, NULL, path, pool);
2078
 
  fprintf(stderr, "   Opening : %s\n", path);
2079
 
  *baton = new_baton;
2080
 
  return (*db->eb->real_editor->open_directory)(path, db->real_baton,
2081
 
                                                base_revision, pool,
2082
 
                                                &new_baton->real_baton);
2083
 
}
2084
 
 
2085
 
static svn_error_t *
2086
 
change_dir_prop(void *dir_baton,
2087
 
                const char *name,
2088
 
                const svn_string_t *value,
2089
 
                apr_pool_t *pool)
2090
 
{
2091
 
  struct item_baton *db = dir_baton;
2092
 
  fprintf(stderr, "      PropSet (%s=%s)\n", name, value ? value->data : "");
2093
 
  return (*db->eb->real_editor->change_dir_prop)(db->real_baton,
2094
 
                                                 name, value, pool);
2095
 
}
2096
 
 
2097
 
static svn_error_t *
2098
 
close_directory(void *baton, apr_pool_t *pool)
2099
 
{
2100
 
  struct item_baton *db = baton;
2101
 
  fprintf(stderr, "   Closing : %s\n", db->path);
2102
 
  return (*db->eb->real_editor->close_directory)(db->real_baton, pool);
2103
 
}
2104
 
 
2105
 
static svn_error_t *
2106
 
abort_edit(void *edit_baton, apr_pool_t *pool)
2107
 
{
2108
 
  struct edit_baton *eb = edit_baton;
2109
 
  fprintf(stderr, "TEST EDIT ABORTED\n");
2110
 
  return (*eb->real_editor->abort_edit)(eb->real_eb, pool);
2111
 
}
2112
 
 
2113
 
static svn_error_t *
2114
 
get_test_editor(const svn_delta_editor_t **editor,
2115
 
                void **edit_baton,
2116
 
                const svn_delta_editor_t *real_editor,
2117
 
                void *real_eb,
2118
 
                const char *base_url,
2119
 
                apr_pool_t *pool)
2120
 
{
2121
 
  svn_delta_editor_t *ed = svn_delta_default_editor(pool);
2122
 
  struct edit_baton *eb = apr_pcalloc(pool, sizeof(*eb));
2123
 
 
2124
 
  eb->path = apr_pstrdup(pool, base_url);
2125
 
  eb->real_editor = real_editor;
2126
 
  eb->real_eb = real_eb;
2127
 
 
2128
 
  /* We don't implement absent_file() or absent_directory() in this
2129
 
     editor, because presumably commit would never send that. */
2130
 
  ed->set_target_revision = set_target_revision;
2131
 
  ed->open_root = open_root;
2132
 
  ed->add_directory = add_directory;
2133
 
  ed->open_directory = open_directory;
2134
 
  ed->close_directory = close_directory;
2135
 
  ed->add_file = add_file;
2136
 
  ed->open_file = open_file;
2137
 
  ed->close_file = close_file;
2138
 
  ed->delete_entry = delete_entry;
2139
 
  ed->apply_textdelta = apply_textdelta;
2140
 
  ed->change_dir_prop = change_dir_prop;
2141
 
  ed->change_file_prop = change_file_prop;
2142
 
  ed->close_edit = close_edit;
2143
 
  ed->abort_edit = abort_edit;
2144
 
 
2145
 
  *editor = ed;
2146
 
  *edit_baton = eb;
2147
 
  return SVN_NO_ERROR;
2148
 
}
2149
 
#endif /* SVN_CLIENT_COMMIT_DEBUG */
2150
 
 
2151
1871
svn_error_t *
2152
1872
svn_client__get_log_msg(const char **log_msg,
2153
1873
                        const char **tmp_file,
2254
1974
    {
2255
1975
      new_revprop_table = apr_hash_make(pool);
2256
1976
    }
2257
 
  apr_hash_set(new_revprop_table, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING,
2258
 
               svn_string_create(log_msg, pool));
 
1977
  svn_hash_sets(new_revprop_table, SVN_PROP_REVISION_LOG,
 
1978
                svn_string_create(log_msg, pool));
2259
1979
  *revprop_table_out = new_revprop_table;
2260
1980
  return SVN_NO_ERROR;
2261
1981
}