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