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;
52299742Sdim  svn_boolean_t clear_changelists;
53299742Sdim  svn_boolean_t metadata_only;
54251881Speter  svn_client_ctx_t *ctx;
55251881Speter};
56251881Speter
57251881Speter/* (Note: All arguments are in the baton above.)
58251881Speter
59251881Speter   Attempt to revert LOCAL_ABSPATH.
60251881Speter
61251881Speter   If DEPTH is svn_depth_empty, revert just the properties on the
62251881Speter   directory; else if svn_depth_files, revert the properties and any
63251881Speter   files immediately under the directory; else if
64251881Speter   svn_depth_immediates, revert all of the preceding plus properties
65251881Speter   on immediate subdirectories; else if svn_depth_infinity, revert
66251881Speter   path and everything under it fully recursively.
67251881Speter
68251881Speter   CHANGELISTS is an array of const char * changelist names, used as a
69251881Speter   restrictive filter on items reverted; that is, don't revert any
70251881Speter   item unless it's a member of one of those changelists.  If
71251881Speter   CHANGELISTS is empty (or altogether NULL), no changelist filtering occurs.
72251881Speter
73251881Speter   Consult CTX to determine whether or not to revert timestamp to the
74251881Speter   time of last commit ('use-commit-times = yes').
75251881Speter
76251881Speter   If PATH is unversioned, return SVN_ERR_UNVERSIONED_RESOURCE. */
77251881Speterstatic svn_error_t *
78251881Speterrevert(void *baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool)
79251881Speter{
80251881Speter  struct revert_with_write_lock_baton *b = baton;
81251881Speter  svn_error_t *err;
82251881Speter
83299742Sdim  err = svn_wc_revert5(b->ctx->wc_ctx,
84251881Speter                       b->local_abspath,
85251881Speter                       b->depth,
86251881Speter                       b->use_commit_times,
87251881Speter                       b->changelists,
88299742Sdim                       b->clear_changelists,
89299742Sdim                       b->metadata_only,
90251881Speter                       b->ctx->cancel_func, b->ctx->cancel_baton,
91251881Speter                       b->ctx->notify_func2, b->ctx->notify_baton2,
92251881Speter                       scratch_pool);
93251881Speter
94251881Speter  if (err)
95251881Speter    {
96251881Speter      /* If target isn't versioned, just send a 'skip'
97251881Speter         notification and move on. */
98251881Speter      if (err->apr_err == SVN_ERR_ENTRY_NOT_FOUND
99251881Speter          || err->apr_err == SVN_ERR_UNVERSIONED_RESOURCE
100251881Speter          || err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
101251881Speter        {
102251881Speter          if (b->ctx->notify_func2)
103299742Sdim            {
104299742Sdim              svn_wc_notify_t *notify;
105299742Sdim
106299742Sdim              notify = svn_wc_create_notify(b->local_abspath,
107299742Sdim                                            svn_wc_notify_skip,
108299742Sdim                                            scratch_pool);
109299742Sdim
110299742Sdim              notify->err = err;
111299742Sdim
112299742Sdim              b->ctx->notify_func2(b->ctx->notify_baton2,
113299742Sdim                                   notify, scratch_pool);
114299742Sdim            }
115251881Speter          svn_error_clear(err);
116251881Speter        }
117251881Speter      else
118251881Speter        return svn_error_trace(err);
119251881Speter    }
120251881Speter
121251881Speter  return SVN_NO_ERROR;
122251881Speter}
123251881Speter
124251881Speter
125251881Spetersvn_error_t *
126299742Sdimsvn_client_revert3(const apr_array_header_t *paths,
127251881Speter                   svn_depth_t depth,
128251881Speter                   const apr_array_header_t *changelists,
129299742Sdim                   svn_boolean_t clear_changelists,
130299742Sdim                   svn_boolean_t metadata_only,
131251881Speter                   svn_client_ctx_t *ctx,
132251881Speter                   apr_pool_t *pool)
133251881Speter{
134299742Sdim  apr_pool_t *iterpool;
135251881Speter  svn_error_t *err = SVN_NO_ERROR;
136251881Speter  int i;
137251881Speter  svn_config_t *cfg;
138251881Speter  svn_boolean_t use_commit_times;
139251881Speter  struct revert_with_write_lock_baton baton;
140251881Speter
141251881Speter  /* Don't even attempt to modify the working copy if any of the
142251881Speter   * targets look like URLs. URLs are invalid input. */
143251881Speter  for (i = 0; i < paths->nelts; i++)
144251881Speter    {
145251881Speter      const char *path = APR_ARRAY_IDX(paths, i, const char *);
146251881Speter
147251881Speter      if (svn_path_is_url(path))
148251881Speter        return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
149251881Speter                                 _("'%s' is not a local path"), path);
150251881Speter    }
151251881Speter
152251881Speter  cfg = ctx->config
153251881Speter        ? svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG)
154251881Speter        : NULL;
155251881Speter
156251881Speter  SVN_ERR(svn_config_get_bool(cfg, &use_commit_times,
157251881Speter                              SVN_CONFIG_SECTION_MISCELLANY,
158251881Speter                              SVN_CONFIG_OPTION_USE_COMMIT_TIMES,
159251881Speter                              FALSE));
160251881Speter
161299742Sdim  iterpool = svn_pool_create(pool);
162251881Speter
163251881Speter  for (i = 0; i < paths->nelts; i++)
164251881Speter    {
165251881Speter      const char *path = APR_ARRAY_IDX(paths, i, const char *);
166251881Speter      const char *local_abspath, *lock_target;
167251881Speter      svn_boolean_t wc_root;
168251881Speter
169299742Sdim      svn_pool_clear(iterpool);
170251881Speter
171251881Speter      /* See if we've been asked to cancel this operation. */
172251881Speter      if ((ctx->cancel_func)
173251881Speter          && ((err = ctx->cancel_func(ctx->cancel_baton))))
174251881Speter        goto errorful;
175251881Speter
176299742Sdim      err = svn_dirent_get_absolute(&local_abspath, path, iterpool);
177251881Speter      if (err)
178251881Speter        goto errorful;
179251881Speter
180251881Speter      baton.local_abspath = local_abspath;
181251881Speter      baton.depth = depth;
182251881Speter      baton.use_commit_times = use_commit_times;
183251881Speter      baton.changelists = changelists;
184299742Sdim      baton.clear_changelists = clear_changelists;
185299742Sdim      baton.metadata_only = metadata_only;
186251881Speter      baton.ctx = ctx;
187251881Speter
188299742Sdim      err = svn_wc__is_wcroot(&wc_root, ctx->wc_ctx, local_abspath, iterpool);
189251881Speter      if (err)
190251881Speter        goto errorful;
191251881Speter      lock_target = wc_root ? local_abspath
192251881Speter                            : svn_dirent_dirname(local_abspath, pool);
193251881Speter      err = svn_wc__call_with_write_lock(revert, &baton, ctx->wc_ctx,
194299742Sdim                                         lock_target, FALSE,
195299742Sdim                                         iterpool, iterpool);
196251881Speter      if (err)
197251881Speter        goto errorful;
198251881Speter    }
199251881Speter
200251881Speter errorful:
201251881Speter
202251881Speter  {
203251881Speter    /* Sleep to ensure timestamp integrity. */
204251881Speter    const char *sleep_path = NULL;
205251881Speter
206251881Speter    /* Only specify a path if we are certain all paths are on the
207251881Speter       same filesystem */
208251881Speter    if (paths->nelts == 1)
209251881Speter      sleep_path = APR_ARRAY_IDX(paths, 0, const char *);
210251881Speter
211299742Sdim    svn_io_sleep_for_timestamps(sleep_path, iterpool);
212251881Speter  }
213251881Speter
214299742Sdim  svn_pool_destroy(iterpool);
215251881Speter
216251881Speter  return svn_error_trace(err);
217251881Speter}
218