1251881Speter/*
2251881Speter * revert.c:  wrapper around wc revert functionality.
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter/* ==================================================================== */
25251881Speter
26251881Speter
27251881Speter
28251881Speter/*** Includes. ***/
29251881Speter
30251881Speter#include "svn_path.h"
31251881Speter#include "svn_wc.h"
32251881Speter#include "svn_client.h"
33251881Speter#include "svn_dirent_uri.h"
34251881Speter#include "svn_hash.h"
35251881Speter#include "svn_pools.h"
36251881Speter#include "svn_error.h"
37251881Speter#include "svn_time.h"
38251881Speter#include "svn_config.h"
39251881Speter#include "client.h"
40251881Speter#include "private/svn_wc_private.h"
41251881Speter
42251881Speter#include "svn_private_config.h"
43251881Speter
44251881Speter
45251881Speter/*** Code. ***/
46251881Speter
47251881Speterstruct revert_with_write_lock_baton {
48251881Speter  const char *local_abspath;
49251881Speter  svn_depth_t depth;
50251881Speter  svn_boolean_t use_commit_times;
51251881Speter  const apr_array_header_t *changelists;
52289180Speter  svn_boolean_t clear_changelists;
53289180Speter  svn_boolean_t metadata_only;
54362181Sdim  svn_boolean_t added_keep_local;
55251881Speter  svn_client_ctx_t *ctx;
56251881Speter};
57251881Speter
58251881Speter/* (Note: All arguments are in the baton above.)
59251881Speter
60362181Sdim   Attempt to revert LOCAL_ABSPATH by calling svn_wc_revert6(), which
61362181Sdim   see for further details.
62251881Speter
63362181Sdim   If the target isn't versioned, send a 'skip' notification and return
64362181Sdim   no error.
65362181Sdim */
66251881Speterstatic svn_error_t *
67251881Speterrevert(void *baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool)
68251881Speter{
69251881Speter  struct revert_with_write_lock_baton *b = baton;
70251881Speter  svn_error_t *err;
71251881Speter
72362181Sdim  err = svn_wc_revert6(b->ctx->wc_ctx,
73251881Speter                       b->local_abspath,
74251881Speter                       b->depth,
75251881Speter                       b->use_commit_times,
76251881Speter                       b->changelists,
77289180Speter                       b->clear_changelists,
78289180Speter                       b->metadata_only,
79362181Sdim                       b->added_keep_local,
80251881Speter                       b->ctx->cancel_func, b->ctx->cancel_baton,
81251881Speter                       b->ctx->notify_func2, b->ctx->notify_baton2,
82251881Speter                       scratch_pool);
83251881Speter
84251881Speter  if (err)
85251881Speter    {
86251881Speter      /* If target isn't versioned, just send a 'skip'
87251881Speter         notification and move on. */
88251881Speter      if (err->apr_err == SVN_ERR_ENTRY_NOT_FOUND
89251881Speter          || err->apr_err == SVN_ERR_UNVERSIONED_RESOURCE
90251881Speter          || err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
91251881Speter        {
92251881Speter          if (b->ctx->notify_func2)
93289180Speter            {
94289180Speter              svn_wc_notify_t *notify;
95289180Speter
96289180Speter              notify = svn_wc_create_notify(b->local_abspath,
97289180Speter                                            svn_wc_notify_skip,
98289180Speter                                            scratch_pool);
99289180Speter
100289180Speter              notify->err = err;
101289180Speter
102289180Speter              b->ctx->notify_func2(b->ctx->notify_baton2,
103289180Speter                                   notify, scratch_pool);
104289180Speter            }
105251881Speter          svn_error_clear(err);
106251881Speter        }
107251881Speter      else
108251881Speter        return svn_error_trace(err);
109251881Speter    }
110251881Speter
111251881Speter  return SVN_NO_ERROR;
112251881Speter}
113251881Speter
114251881Speter
115251881Spetersvn_error_t *
116362181Sdimsvn_client_revert4(const apr_array_header_t *paths,
117251881Speter                   svn_depth_t depth,
118251881Speter                   const apr_array_header_t *changelists,
119289180Speter                   svn_boolean_t clear_changelists,
120289180Speter                   svn_boolean_t metadata_only,
121362181Sdim                   svn_boolean_t added_keep_local,
122251881Speter                   svn_client_ctx_t *ctx,
123251881Speter                   apr_pool_t *pool)
124251881Speter{
125289180Speter  apr_pool_t *iterpool;
126251881Speter  svn_error_t *err = SVN_NO_ERROR;
127251881Speter  int i;
128251881Speter  svn_config_t *cfg;
129251881Speter  svn_boolean_t use_commit_times;
130251881Speter  struct revert_with_write_lock_baton baton;
131251881Speter
132251881Speter  /* Don't even attempt to modify the working copy if any of the
133251881Speter   * targets look like URLs. URLs are invalid input. */
134251881Speter  for (i = 0; i < paths->nelts; i++)
135251881Speter    {
136251881Speter      const char *path = APR_ARRAY_IDX(paths, i, const char *);
137251881Speter
138251881Speter      if (svn_path_is_url(path))
139251881Speter        return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
140251881Speter                                 _("'%s' is not a local path"), path);
141251881Speter    }
142251881Speter
143251881Speter  cfg = ctx->config
144251881Speter        ? svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG)
145251881Speter        : NULL;
146251881Speter
147251881Speter  SVN_ERR(svn_config_get_bool(cfg, &use_commit_times,
148251881Speter                              SVN_CONFIG_SECTION_MISCELLANY,
149251881Speter                              SVN_CONFIG_OPTION_USE_COMMIT_TIMES,
150251881Speter                              FALSE));
151251881Speter
152289180Speter  iterpool = svn_pool_create(pool);
153251881Speter
154251881Speter  for (i = 0; i < paths->nelts; i++)
155251881Speter    {
156251881Speter      const char *path = APR_ARRAY_IDX(paths, i, const char *);
157251881Speter      const char *local_abspath, *lock_target;
158251881Speter      svn_boolean_t wc_root;
159251881Speter
160289180Speter      svn_pool_clear(iterpool);
161251881Speter
162251881Speter      /* See if we've been asked to cancel this operation. */
163251881Speter      if ((ctx->cancel_func)
164251881Speter          && ((err = ctx->cancel_func(ctx->cancel_baton))))
165251881Speter        goto errorful;
166251881Speter
167289180Speter      err = svn_dirent_get_absolute(&local_abspath, path, iterpool);
168251881Speter      if (err)
169251881Speter        goto errorful;
170251881Speter
171251881Speter      baton.local_abspath = local_abspath;
172251881Speter      baton.depth = depth;
173251881Speter      baton.use_commit_times = use_commit_times;
174251881Speter      baton.changelists = changelists;
175289180Speter      baton.clear_changelists = clear_changelists;
176289180Speter      baton.metadata_only = metadata_only;
177362181Sdim      baton.added_keep_local = added_keep_local;
178251881Speter      baton.ctx = ctx;
179251881Speter
180289180Speter      err = svn_wc__is_wcroot(&wc_root, ctx->wc_ctx, local_abspath, iterpool);
181251881Speter      if (err)
182251881Speter        goto errorful;
183251881Speter      lock_target = wc_root ? local_abspath
184251881Speter                            : svn_dirent_dirname(local_abspath, pool);
185251881Speter      err = svn_wc__call_with_write_lock(revert, &baton, ctx->wc_ctx,
186289180Speter                                         lock_target, FALSE,
187289180Speter                                         iterpool, iterpool);
188251881Speter      if (err)
189251881Speter        goto errorful;
190251881Speter    }
191251881Speter
192251881Speter errorful:
193251881Speter
194251881Speter  {
195251881Speter    /* Sleep to ensure timestamp integrity. */
196251881Speter    const char *sleep_path = NULL;
197251881Speter
198251881Speter    /* Only specify a path if we are certain all paths are on the
199251881Speter       same filesystem */
200251881Speter    if (paths->nelts == 1)
201251881Speter      sleep_path = APR_ARRAY_IDX(paths, 0, const char *);
202251881Speter
203289180Speter    svn_io_sleep_for_timestamps(sleep_path, iterpool);
204251881Speter  }
205251881Speter
206289180Speter  svn_pool_destroy(iterpool);
207251881Speter
208251881Speter  return svn_error_trace(err);
209251881Speter}
210