static svn_error_t * obtain_lock(const char *path, svn_boolean_t recursive, apr_pool_t *scratch_pool) { const char *local_abspath; svn_wc_context_t *wc_ctx; SVN_ERR(svn_path_cstring_to_utf8(&path, path, scratch_pool)); SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool)); SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, scratch_pool, scratch_pool)); if (recursive) { /* The WC-NG way */ SVN_ERR(svn_wc__acquire_write_lock(NULL, wc_ctx, local_abspath, FALSE, scratch_pool, scratch_pool)); } else { SVN_ERR(svn_wc__db_wclock_obtain(wc_ctx->db, local_abspath, 0, FALSE, scratch_pool)); } SVN_ERR(svn_cmdline_printf(scratch_pool, "Lock on '%s' obtained, and we " "are not going to release it.\n", svn_dirent_local_style(local_abspath, scratch_pool))); return SVN_NO_ERROR; }
svn_error_t * svn_client__switch_internal(svn_revnum_t *result_rev, const char *path, const char *switch_url, const svn_opt_revision_t *peg_revision, const svn_opt_revision_t *revision, svn_depth_t depth, svn_boolean_t depth_is_sticky, svn_boolean_t ignore_externals, svn_boolean_t allow_unver_obstructions, svn_boolean_t ignore_ancestry, svn_boolean_t *timestamp_sleep, svn_client_ctx_t *ctx, apr_pool_t *pool) { const char *local_abspath, *anchor_abspath; svn_boolean_t acquired_lock; svn_error_t *err, *err1, *err2; apr_hash_t *conflicted_paths = ctx->conflict_func2 ? apr_hash_make(pool) : NULL; SVN_ERR_ASSERT(path); SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool)); /* Rely on svn_wc__acquire_write_lock setting ANCHOR_ABSPATH even when it returns SVN_ERR_WC_LOCKED */ err = svn_wc__acquire_write_lock(&anchor_abspath, ctx->wc_ctx, local_abspath, TRUE, pool, pool); if (err && err->apr_err != SVN_ERR_WC_LOCKED) return svn_error_trace(err); acquired_lock = (err == SVN_NO_ERROR); svn_error_clear(err); err1 = switch_internal(result_rev, conflicted_paths, local_abspath, anchor_abspath, switch_url, peg_revision, revision, depth, depth_is_sticky, ignore_externals, allow_unver_obstructions, ignore_ancestry, timestamp_sleep, ctx, pool); /* Give the conflict resolver callback the opportunity to * resolve any conflicts that were raised. */ if (! err1 && ctx->conflict_func2) { err1 = svn_client__resolve_conflicts(NULL, conflicted_paths, ctx, pool); } if (acquired_lock) err2 = svn_wc__release_write_lock(ctx->wc_ctx, anchor_abspath, pool); else err2 = SVN_NO_ERROR; return svn_error_compose_create(err1, err2); }
svn_error_t * sbox_wc_add(svn_test__sandbox_t *b, const char *path) { const char *parent_abspath; path = sbox_wc_path(b, path); parent_abspath = svn_dirent_dirname(path, b->pool); SVN_ERR(svn_wc__acquire_write_lock(NULL, b->wc_ctx, parent_abspath, FALSE, b->pool, b->pool)); SVN_ERR(svn_wc_add_from_disk2(b->wc_ctx, path, NULL /*props*/, NULL, NULL, b->pool)); SVN_ERR(svn_wc__release_write_lock(b->wc_ctx, parent_abspath, b->pool)); return SVN_NO_ERROR; }
svn_error_t * sbox_wc_copy(svn_test__sandbox_t *b, const char *from_path, const char *to_path) { const char *parent_abspath; from_path = sbox_wc_path(b, from_path); to_path = sbox_wc_path(b, to_path); parent_abspath = svn_dirent_dirname(to_path, b->pool); SVN_ERR(svn_wc__acquire_write_lock(NULL, b->wc_ctx, parent_abspath, FALSE, b->pool, b->pool)); SVN_ERR(svn_wc_copy3(b->wc_ctx, from_path, to_path, FALSE, NULL, NULL, NULL, NULL, b->pool)); SVN_ERR(svn_wc__release_write_lock(b->wc_ctx, parent_abspath, b->pool)); return SVN_NO_ERROR; }
svn_error_t * svn_client__switch_internal(svn_revnum_t *result_rev, const char *path, const char *switch_url, const svn_opt_revision_t *peg_revision, const svn_opt_revision_t *revision, svn_depth_t depth, svn_boolean_t depth_is_sticky, svn_boolean_t ignore_externals, svn_boolean_t allow_unver_obstructions, svn_boolean_t ignore_ancestry, svn_boolean_t *timestamp_sleep, svn_client_ctx_t *ctx, apr_pool_t *pool) { const char *local_abspath, *anchor_abspath; svn_boolean_t acquired_lock; svn_error_t *err, *err1, *err2; SVN_ERR_ASSERT(path); SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool)); /* Rely on svn_wc__acquire_write_lock setting ANCHOR_ABSPATH even when it returns SVN_ERR_WC_LOCKED */ err = svn_wc__acquire_write_lock(&anchor_abspath, ctx->wc_ctx, local_abspath, TRUE, pool, pool); if (err && err->apr_err != SVN_ERR_WC_LOCKED) return svn_error_trace(err); acquired_lock = (err == SVN_NO_ERROR); svn_error_clear(err); err1 = switch_internal(result_rev, local_abspath, anchor_abspath, switch_url, peg_revision, revision, depth, depth_is_sticky, ignore_externals, allow_unver_obstructions, ignore_ancestry, timestamp_sleep, ctx, pool); if (acquired_lock) err2 = svn_wc__release_write_lock(ctx->wc_ctx, anchor_abspath, pool); else err2 = SVN_NO_ERROR; return svn_error_compose_create(err1, err2); }
svn_error_t * sbox_wc_exclude(svn_test__sandbox_t *b, const char *path) { const char *abspath = sbox_wc_path(b, path); const char *lock_root_abspath; SVN_ERR(svn_wc__acquire_write_lock(&lock_root_abspath, b->wc_ctx, abspath, TRUE, b->pool, b->pool)); SVN_ERR(svn_wc_exclude(b->wc_ctx, abspath, NULL, NULL, /* cancel baton + func */ NULL, NULL, /* notify baton + func */ b->pool)); SVN_ERR(svn_wc__release_write_lock(b->wc_ctx, lock_root_abspath, b->pool)); return SVN_NO_ERROR; }
svn_error_t * sbox_wc_revert(svn_test__sandbox_t *b, const char *path, svn_depth_t depth) { const char *abspath = sbox_wc_path(b, path); const char *dir_abspath; const char *lock_root_abspath; if (strcmp(abspath, b->wc_abspath)) dir_abspath = svn_dirent_dirname(abspath, b->pool); else dir_abspath = abspath; SVN_ERR(svn_wc__acquire_write_lock(&lock_root_abspath, b->wc_ctx, dir_abspath, FALSE /* lock_anchor */, b->pool, b->pool)); SVN_ERR(svn_wc_revert4(b->wc_ctx, abspath, depth, FALSE, NULL, NULL, NULL, /* cancel baton + func */ NULL, NULL, /* notify baton + func */ b->pool)); SVN_ERR(svn_wc__release_write_lock(b->wc_ctx, lock_root_abspath, b->pool)); return SVN_NO_ERROR; }
/* Remove the directory at LOCAL_ABSPATH from revision control, and do the * same to any revision controlled directories underneath LOCAL_ABSPATH * (including directories not referred to by parent svn administrative areas); * then if LOCAL_ABSPATH is empty afterwards, remove it, else rename it to a * unique name in the same parent directory. * * Pass CANCEL_FUNC, CANCEL_BATON to svn_wc_remove_from_revision_control. * * Use SCRATCH_POOL for all temporary allocation. */ static svn_error_t * relegate_dir_external(svn_wc_context_t *wc_ctx, const char *wri_abspath, const char *local_abspath, svn_cancel_func_t cancel_func, void *cancel_baton, svn_wc_notify_func2_t notify_func, void *notify_baton, apr_pool_t *scratch_pool) { svn_error_t *err = SVN_NO_ERROR; SVN_ERR(svn_wc__acquire_write_lock(NULL, wc_ctx, local_abspath, FALSE, scratch_pool, scratch_pool)); err = svn_wc__external_remove(wc_ctx, wri_abspath, local_abspath, FALSE, cancel_func, cancel_baton, scratch_pool); if (err && (err->apr_err == SVN_ERR_WC_LEFT_LOCAL_MOD)) { const char *parent_dir; const char *dirname; const char *new_path; svn_error_clear(err); err = SVN_NO_ERROR; svn_dirent_split(&parent_dir, &dirname, local_abspath, scratch_pool); /* Reserve the new dir name. */ SVN_ERR(svn_io_open_uniquely_named(NULL, &new_path, parent_dir, dirname, ".OLD", svn_io_file_del_none, scratch_pool, scratch_pool)); /* Sigh... We must fall ever so slightly from grace. Ideally, there would be no window, however brief, when we don't have a reservation on the new name. Unfortunately, at least in the Unix (Linux?) version of apr_file_rename(), you can't rename a directory over a file, because it's just calling stdio rename(), which says: ENOTDIR A component used as a directory in oldpath or newpath path is not, in fact, a directory. Or, oldpath is a directory, and newpath exists but is not a directory So instead, we get the name, then remove the file (ugh), then rename the directory, hoping that nobody has gotten that name in the meantime -- which would never happen in real life, so no big deal. */ /* Do our best, but no biggy if it fails. The rename will fail. */ svn_error_clear(svn_io_remove_file2(new_path, TRUE, scratch_pool)); /* Rename. If this is still a working copy we should use the working copy rename function (to release open handles) */ err = svn_wc__rename_wc(wc_ctx, local_abspath, new_path, scratch_pool); if (err && err->apr_err == SVN_ERR_WC_PATH_UNEXPECTED_STATUS) { svn_error_clear(err); /* And if it is no longer a working copy, we should just rename it */ err = svn_io_file_rename(local_abspath, new_path, scratch_pool); } /* ### TODO: We should notify the user about the rename */ if (notify_func) { svn_wc_notify_t *notify; notify = svn_wc_create_notify(err ? local_abspath : new_path, svn_wc_notify_left_local_modifications, scratch_pool); notify->kind = svn_node_dir; notify->err = err; notify_func(notify_baton, notify, scratch_pool); } } return svn_error_trace(err); }
svn_error_t * svn_client__update_internal(svn_revnum_t *result_rev, const char *local_abspath, const svn_opt_revision_t *revision, svn_depth_t depth, svn_boolean_t depth_is_sticky, svn_boolean_t ignore_externals, svn_boolean_t allow_unver_obstructions, svn_boolean_t adds_as_modification, svn_boolean_t make_parents, svn_boolean_t innerupdate, svn_boolean_t *timestamp_sleep, svn_client_ctx_t *ctx, apr_pool_t *pool) { const char *anchor_abspath, *lockroot_abspath; svn_error_t *err; svn_opt_revision_t peg_revision = *revision; apr_hash_t *conflicted_paths = ctx->conflict_func2 ? apr_hash_make(pool) : NULL; SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); SVN_ERR_ASSERT(! (innerupdate && make_parents)); if (make_parents) { int i; const char *parent_abspath = local_abspath; apr_array_header_t *missing_parents = apr_array_make(pool, 4, sizeof(const char *)); while (1) { /* Try to lock. If we can't lock because our target (or its parent) isn't a working copy, we'll try to walk up the tree to find a working copy, remembering this path's parent as one we need to flesh out. */ err = svn_wc__acquire_write_lock(&lockroot_abspath, ctx->wc_ctx, parent_abspath, !innerupdate, pool, pool); if (!err) break; if ((err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY) || svn_dirent_is_root(parent_abspath, strlen(parent_abspath))) return err; svn_error_clear(err); /* Remember the parent of our update target as a missing parent. */ parent_abspath = svn_dirent_dirname(parent_abspath, pool); APR_ARRAY_PUSH(missing_parents, const char *) = parent_abspath; } /* Run 'svn up --depth=empty' (effectively) on the missing parents, if any. */ anchor_abspath = lockroot_abspath; for (i = missing_parents->nelts - 1; i >= 0; i--) { const char *missing_parent = APR_ARRAY_IDX(missing_parents, i, const char *); err = update_internal(result_rev, conflicted_paths, missing_parent, anchor_abspath, &peg_revision, svn_depth_empty, FALSE, ignore_externals, allow_unver_obstructions, adds_as_modification, timestamp_sleep, FALSE, ctx, pool); if (err) goto cleanup; anchor_abspath = missing_parent; /* If we successfully updated a missing parent, let's re-use the returned revision number for future updates for the sake of consistency. */ peg_revision.kind = svn_opt_revision_number; peg_revision.value.number = *result_rev; } } else {
FALSE, ctx, pool); if (err) goto cleanup; anchor_abspath = missing_parent; /* If we successfully updated a missing parent, let's re-use the returned revision number for future updates for the sake of consistency. */ peg_revision.kind = svn_opt_revision_number; peg_revision.value.number = *result_rev; } } else { SVN_ERR(svn_wc__acquire_write_lock(&lockroot_abspath, ctx->wc_ctx, local_abspath, !innerupdate, pool, pool)); anchor_abspath = lockroot_abspath; } err = update_internal(result_rev, conflicted_paths, local_abspath, anchor_abspath, &peg_revision, depth, depth_is_sticky, ignore_externals, allow_unver_obstructions, adds_as_modification, timestamp_sleep, TRUE, ctx, pool); /* Give the conflict resolver callback the opportunity to * resolve any conflicts that were raised. */ if (! err && ctx->conflict_func2) {