1 /*
2  * atomic-ra-revprop-change.c :  wrapper around svn_ra_change_rev_prop2()
3  *
4  * ====================================================================
5  *    Licensed to the Apache Software Foundation (ASF) under one
6  *    or more contributor license agreements.  See the NOTICE file
7  *    distributed with this work for additional information
8  *    regarding copyright ownership.  The ASF licenses this file
9  *    to you under the Apache License, Version 2.0 (the
10  *    "License"); you may not use this file except in compliance
11  *    with the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  *    Unless required by applicable law or agreed to in writing,
16  *    software distributed under the License is distributed on an
17  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18  *    KIND, either express or implied.  See the License for the
19  *    specific language governing permissions and limitations
20  *    under the License.
21  * ====================================================================
22  */
23 
24 #include <stdlib.h>
25 #include <stdio.h>
26 
27 #include <apr_pools.h>
28 #include <apr_general.h>
29 
30 #include "svn_types.h"
31 #include "svn_pools.h"
32 #include "svn_dirent_uri.h"
33 #include "svn_ra.h"
34 #include "svn_cmdline.h"
35 
36 #include "private/svn_skel.h"
37 
38 #include "svn_private_config.h"
39 
40 
41 #define KEY_OLD_PROPVAL "old_value_p"
42 #define KEY_NEW_PROPVAL "value"
43 
44 #define USAGE_MSG \
45   "Usage: %s URL REVISION PROPNAME VALUES_SKEL WANT_ERROR CONFIG_DIR\n" \
46   "\n" \
47   "VALUES_SKEL is a proplist skel containing pseudo-properties '%s' \n" \
48   "and '%s'.  A pseudo-property missing from the skel is interpreted \n" \
49   "as unset.\n" \
50   "\n" \
51   "WANT_ERROR is 1 if the propchange is expected to fail due to the atomicity,"\
52   "and 0 if it is expected to succeed.  If the expectation matches reality," \
53   "the exit code shall be zero.\n"
54 
55 
56 static svn_error_t *
construct_auth_baton(svn_auth_baton_t ** auth_baton_p,const char * config_dir,apr_pool_t * pool)57 construct_auth_baton(svn_auth_baton_t **auth_baton_p,
58                      const char *config_dir,
59                      apr_pool_t *pool)
60 {
61   SVN_ERR(svn_cmdline_create_auth_baton2(auth_baton_p,
62                                          TRUE  /* non_interactive */,
63                                          "jrandom", "rayjandom",
64                                          config_dir,
65                                          TRUE  /* no_auth_cache */,
66                                          FALSE /* trust_server_cert */,
67                                          FALSE, FALSE, FALSE, FALSE,
68                                          NULL, NULL, NULL, pool));
69   return SVN_NO_ERROR;
70 }
71 
72 static svn_error_t *
construct_config(apr_hash_t ** config_p,const char * config_dir,apr_pool_t * pool)73 construct_config(apr_hash_t **config_p,
74                  const char *config_dir,
75                  apr_pool_t *pool)
76 {
77   SVN_ERR(svn_config_get_config(config_p, config_dir, pool));
78 
79   return SVN_NO_ERROR;
80 }
81 
82 static svn_error_t *
change_rev_prop(const char * url,svn_revnum_t revision,const char * propname,const svn_string_t * propval,const svn_string_t * old_value,svn_boolean_t want_error,const char * config_dir,apr_pool_t * pool)83 change_rev_prop(const char *url,
84                 svn_revnum_t revision,
85                 const char *propname,
86                 const svn_string_t *propval,
87                 const svn_string_t *old_value,
88                 svn_boolean_t want_error,
89                 const char *config_dir,
90                 apr_pool_t *pool)
91 {
92   svn_ra_callbacks2_t *callbacks;
93   svn_ra_session_t *sess;
94   apr_hash_t *config;
95   svn_boolean_t capable;
96   svn_error_t *err;
97 
98   SVN_ERR(svn_ra_create_callbacks(&callbacks, pool));
99   SVN_ERR(construct_auth_baton(&callbacks->auth_baton, config_dir, pool));
100   SVN_ERR(construct_config(&config, config_dir, pool));
101 
102   SVN_ERR(svn_ra_open5(&sess, NULL, NULL, url, NULL,
103                        callbacks, NULL /* baton */, config, pool));
104 
105   SVN_ERR(svn_ra_has_capability(sess, &capable,
106                                 SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
107                                 pool));
108   if (capable)
109     {
110       err = svn_ra_change_rev_prop2(sess, revision, propname,
111                                     &old_value, propval, pool);
112 
113       if (want_error && err
114           && svn_error_find_cause(err, SVN_ERR_FS_PROP_BASEVALUE_MISMATCH))
115         {
116           /* Expectation was matched.  Get out. */
117           svn_error_clear(err);
118           return SVN_NO_ERROR;
119         }
120       else if (! want_error && ! err)
121         /* Expectation was matched.  Get out. */
122         return SVN_NO_ERROR;
123       else if (want_error && ! err)
124         return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
125                                 "An error was expected but not seen");
126       else
127         /* A real (non-SVN_ERR_FS_PROP_BASEVALUE_MISMATCH) error. */
128         return svn_error_trace(err);
129     }
130   else
131     /* Running under --server-minor-version? */
132     return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
133                             "Server doesn't advertise "
134                             "SVN_RA_CAPABILITY_ATOMIC_REVPROPS");
135 }
136 
137 /* Parse SKEL_CSTR according to the description in USAGE_MSG. */
138 static svn_error_t *
extract_values_from_skel(svn_string_t ** old_propval_p,svn_string_t ** propval_p,const char * skel_cstr,apr_pool_t * pool)139 extract_values_from_skel(svn_string_t **old_propval_p,
140                          svn_string_t **propval_p,
141                          const char *skel_cstr,
142                          apr_pool_t *pool)
143 {
144   apr_hash_t *proplist;
145   svn_skel_t *skel;
146 
147   skel = svn_skel__parse(skel_cstr, strlen(skel_cstr), pool);
148   SVN_ERR(svn_skel__parse_proplist(&proplist, skel, pool));
149   *old_propval_p = apr_hash_get(proplist, KEY_OLD_PROPVAL, APR_HASH_KEY_STRING);
150   *propval_p = apr_hash_get(proplist, KEY_NEW_PROPVAL, APR_HASH_KEY_STRING);
151 
152   return SVN_NO_ERROR;
153 }
154 
155 int
main(int argc,const char * argv[])156 main(int argc, const char *argv[])
157 {
158   apr_pool_t *pool;
159   int exit_code = EXIT_SUCCESS;
160   svn_error_t *err;
161   const char *url;
162   svn_revnum_t revision;
163   const char *propname;
164   svn_string_t *propval;
165   svn_string_t *old_propval;
166   char *digits_end = NULL;
167   svn_boolean_t want_error;
168   const char *config_dir;
169 
170   if (argc != 7)
171     {
172       fprintf(stderr, USAGE_MSG, argv[0], KEY_OLD_PROPVAL, KEY_NEW_PROPVAL);
173       exit(1);
174     }
175 
176   if (apr_initialize() != APR_SUCCESS)
177     {
178       fprintf(stderr, "apr_initialize() failed.\n");
179       exit(1);
180     }
181 
182   /* set up the global pool */
183   pool = svn_pool_create(NULL);
184 
185   /* Parse argv. */
186   url = svn_uri_canonicalize(argv[1], pool);
187   revision = strtol(argv[2], &digits_end, 10);
188   propname = argv[3];
189   SVN_INT_ERR(extract_values_from_skel(&old_propval, &propval, argv[4], pool));
190   want_error = !strcmp(argv[5], "1");
191   config_dir = svn_dirent_canonicalize(argv[6], pool);
192 
193 
194   if ((! SVN_IS_VALID_REVNUM(revision)) || (! digits_end) || *digits_end)
195     SVN_INT_ERR(svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
196                                  _("Invalid revision number supplied")));
197 
198   /* Do something. */
199   err = change_rev_prop(url, revision, propname, propval, old_propval,
200                         want_error, config_dir, pool);
201   if (err)
202     {
203       svn_handle_error2(err, stderr, FALSE, "atomic-ra-revprop-change: ");
204       svn_error_clear(err);
205       exit_code = EXIT_FAILURE;
206     }
207 
208   /* Clean up, and get outta here */
209   svn_pool_destroy(pool);
210   apr_terminate();
211 
212   return exit_code;
213 }
214