1 /*
2 * svn_types.c : Implementation for Subversion's data types.
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 <apr_pools.h>
25 #include <apr_uuid.h>
26
27 #include "svn_hash.h"
28 #include "svn_types.h"
29 #include "svn_error.h"
30 #include "svn_string.h"
31 #include "svn_props.h"
32 #include "svn_private_config.h"
33
34 #include "private/svn_dep_compat.h"
35 #include "private/svn_string_private.h"
36
37 svn_error_t *
svn_revnum_parse(svn_revnum_t * rev,const char * str,const char ** endptr)38 svn_revnum_parse(svn_revnum_t *rev,
39 const char *str,
40 const char **endptr)
41 {
42 const char *end;
43
44 svn_revnum_t result = (svn_revnum_t)svn__strtoul(str, &end);
45
46 if (endptr)
47 *endptr = str;
48
49 if (str == end)
50 return svn_error_createf
51 (SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
52 *str == '-' ? _("Negative revision number found parsing '%s'")
53 : _("Invalid revision number found parsing '%s'"),
54 str);
55
56 /* a revision number with more than 9 digits is suspicious.
57 Have a closer look at those. */
58 if (str + 10 <= end)
59 {
60 /* we support 32 bit revision numbers only. check for overflows */
61 if (str + 10 < end)
62 return svn_error_createf
63 (SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
64 _("Revision number longer than 10 digits '%s'"), str);
65
66 /* we support 32 bit revision numbers only. check for overflows */
67 if (*str > '2' || (apr_uint32_t)result > APR_INT32_MAX)
68 return svn_error_createf
69 (SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
70 _("Revision number too large '%s'"), str);
71 }
72
73 if (endptr)
74 *endptr = end;
75
76 *rev = result;
77
78 return SVN_NO_ERROR;
79 }
80
81 const char *
svn_uuid_generate(apr_pool_t * pool)82 svn_uuid_generate(apr_pool_t *pool)
83 {
84 apr_uuid_t uuid;
85 char *uuid_str = apr_pcalloc(pool, APR_UUID_FORMATTED_LENGTH + 1);
86 apr_uuid_get(&uuid);
87 apr_uuid_format(uuid_str, &uuid);
88 return uuid_str;
89 }
90
91 const char *
svn_depth_to_word(svn_depth_t depth)92 svn_depth_to_word(svn_depth_t depth)
93 {
94 switch (depth)
95 {
96 case svn_depth_exclude:
97 return "exclude";
98 case svn_depth_unknown:
99 return "unknown";
100 case svn_depth_empty:
101 return "empty";
102 case svn_depth_files:
103 return "files";
104 case svn_depth_immediates:
105 return "immediates";
106 case svn_depth_infinity:
107 return "infinity";
108 default:
109 return "INVALID-DEPTH";
110 }
111 }
112
113
114 svn_depth_t
svn_depth_from_word(const char * word)115 svn_depth_from_word(const char *word)
116 {
117 if (strcmp(word, "exclude") == 0)
118 return svn_depth_exclude;
119 if (strcmp(word, "unknown") == 0)
120 return svn_depth_unknown;
121 if (strcmp(word, "empty") == 0)
122 return svn_depth_empty;
123 if (strcmp(word, "files") == 0)
124 return svn_depth_files;
125 if (strcmp(word, "immediates") == 0)
126 return svn_depth_immediates;
127 if (strcmp(word, "infinity") == 0)
128 return svn_depth_infinity;
129 /* There's no special value for invalid depth, and no convincing
130 reason to make one yet, so just fall back to unknown depth.
131 If you ever change that convention, check callers to make sure
132 they're not depending on it (e.g., option parsing in main() ).
133 */
134 return svn_depth_unknown;
135 }
136
137 const char *
svn_node_kind_to_word(svn_node_kind_t kind)138 svn_node_kind_to_word(svn_node_kind_t kind)
139 {
140 switch (kind)
141 {
142 case svn_node_none:
143 return "none";
144 case svn_node_file:
145 return "file";
146 case svn_node_dir:
147 return "dir";
148 case svn_node_symlink:
149 return "symlink";
150 case svn_node_unknown:
151 default:
152 return "unknown";
153 }
154 }
155
156
157 svn_node_kind_t
svn_node_kind_from_word(const char * word)158 svn_node_kind_from_word(const char *word)
159 {
160 if (word == NULL)
161 return svn_node_unknown;
162
163 if (strcmp(word, "none") == 0)
164 return svn_node_none;
165 else if (strcmp(word, "file") == 0)
166 return svn_node_file;
167 else if (strcmp(word, "dir") == 0)
168 return svn_node_dir;
169 else if (strcmp(word, "symlink") == 0)
170 return svn_node_symlink;
171 else
172 /* This also handles word == "unknown" */
173 return svn_node_unknown;
174 }
175
176 const char *
svn_tristate__to_word(svn_tristate_t tristate)177 svn_tristate__to_word(svn_tristate_t tristate)
178 {
179 switch (tristate)
180 {
181 case svn_tristate_false:
182 return "false";
183 case svn_tristate_true:
184 return "true";
185 case svn_tristate_unknown:
186 default:
187 return NULL;
188 }
189 }
190
191 svn_tristate_t
svn_tristate__from_word(const char * word)192 svn_tristate__from_word(const char *word)
193 {
194 if (word == NULL)
195 return svn_tristate_unknown;
196 else if (0 == svn_cstring_casecmp(word, "true")
197 || 0 == svn_cstring_casecmp(word, "yes")
198 || 0 == svn_cstring_casecmp(word, "on")
199 || 0 == strcmp(word, "1"))
200 return svn_tristate_true;
201 else if (0 == svn_cstring_casecmp(word, "false")
202 || 0 == svn_cstring_casecmp(word, "no")
203 || 0 == svn_cstring_casecmp(word, "off")
204 || 0 == strcmp(word, "0"))
205 return svn_tristate_false;
206
207 return svn_tristate_unknown;
208 }
209
210 svn_commit_info_t *
svn_create_commit_info(apr_pool_t * pool)211 svn_create_commit_info(apr_pool_t *pool)
212 {
213 svn_commit_info_t *commit_info
214 = apr_pcalloc(pool, sizeof(*commit_info));
215
216 commit_info->revision = SVN_INVALID_REVNUM;
217 /* All other fields were initialized to NULL above. */
218
219 return commit_info;
220 }
221
222 svn_commit_info_t *
svn_commit_info_dup(const svn_commit_info_t * src_commit_info,apr_pool_t * pool)223 svn_commit_info_dup(const svn_commit_info_t *src_commit_info,
224 apr_pool_t *pool)
225 {
226 svn_commit_info_t *dst_commit_info
227 = apr_palloc(pool, sizeof(*dst_commit_info));
228
229 dst_commit_info->date = src_commit_info->date
230 ? apr_pstrdup(pool, src_commit_info->date) : NULL;
231 dst_commit_info->author = src_commit_info->author
232 ? apr_pstrdup(pool, src_commit_info->author) : NULL;
233 dst_commit_info->revision = src_commit_info->revision;
234 dst_commit_info->post_commit_err = src_commit_info->post_commit_err
235 ? apr_pstrdup(pool, src_commit_info->post_commit_err) : NULL;
236 dst_commit_info->repos_root = src_commit_info->repos_root
237 ? apr_pstrdup(pool, src_commit_info->repos_root) : NULL;
238
239 return dst_commit_info;
240 }
241
242 svn_log_changed_path2_t *
svn_log_changed_path2_create(apr_pool_t * pool)243 svn_log_changed_path2_create(apr_pool_t *pool)
244 {
245 svn_log_changed_path2_t *new_changed_path
246 = apr_pcalloc(pool, sizeof(*new_changed_path));
247
248 new_changed_path->text_modified = svn_tristate_unknown;
249 new_changed_path->props_modified = svn_tristate_unknown;
250
251 return new_changed_path;
252 }
253
254 svn_log_changed_path2_t *
svn_log_changed_path2_dup(const svn_log_changed_path2_t * changed_path,apr_pool_t * pool)255 svn_log_changed_path2_dup(const svn_log_changed_path2_t *changed_path,
256 apr_pool_t *pool)
257 {
258 svn_log_changed_path2_t *new_changed_path
259 = apr_palloc(pool, sizeof(*new_changed_path));
260
261 *new_changed_path = *changed_path;
262
263 if (new_changed_path->copyfrom_path)
264 new_changed_path->copyfrom_path =
265 apr_pstrdup(pool, new_changed_path->copyfrom_path);
266
267 return new_changed_path;
268 }
269
270 svn_dirent_t *
svn_dirent_create(apr_pool_t * result_pool)271 svn_dirent_create(apr_pool_t *result_pool)
272 {
273 svn_dirent_t *new_dirent = apr_pcalloc(result_pool, sizeof(*new_dirent));
274
275 new_dirent->kind = svn_node_unknown;
276 new_dirent->size = SVN_INVALID_FILESIZE;
277 new_dirent->created_rev = SVN_INVALID_REVNUM;
278 new_dirent->time = 0;
279 new_dirent->last_author = NULL;
280
281 return new_dirent;
282 }
283
284 svn_dirent_t *
svn_dirent_dup(const svn_dirent_t * dirent,apr_pool_t * pool)285 svn_dirent_dup(const svn_dirent_t *dirent,
286 apr_pool_t *pool)
287 {
288 svn_dirent_t *new_dirent = apr_palloc(pool, sizeof(*new_dirent));
289
290 *new_dirent = *dirent;
291
292 new_dirent->last_author = apr_pstrdup(pool, dirent->last_author);
293
294 return new_dirent;
295 }
296
297 svn_log_entry_t *
svn_log_entry_create(apr_pool_t * pool)298 svn_log_entry_create(apr_pool_t *pool)
299 {
300 svn_log_entry_t *log_entry = apr_pcalloc(pool, sizeof(*log_entry));
301
302 return log_entry;
303 }
304
305 svn_log_entry_t *
svn_log_entry_dup(const svn_log_entry_t * log_entry,apr_pool_t * pool)306 svn_log_entry_dup(const svn_log_entry_t *log_entry, apr_pool_t *pool)
307 {
308 apr_hash_index_t *hi;
309 svn_log_entry_t *new_entry = apr_palloc(pool, sizeof(*new_entry));
310
311 *new_entry = *log_entry;
312
313 if (log_entry->revprops)
314 new_entry->revprops = svn_prop_hash_dup(log_entry->revprops, pool);
315
316 if (log_entry->changed_paths2)
317 {
318 new_entry->changed_paths2 = apr_hash_make(pool);
319
320 for (hi = apr_hash_first(pool, log_entry->changed_paths2);
321 hi; hi = apr_hash_next(hi))
322 {
323 const void *key;
324 void *change;
325
326 apr_hash_this(hi, &key, NULL, &change);
327
328 svn_hash_sets(new_entry->changed_paths2, apr_pstrdup(pool, key),
329 svn_log_changed_path2_dup(change, pool));
330 }
331 }
332
333 /* We can't copy changed_paths by itself without using deprecated code,
334 but we don't have to, as this function was new after the introduction
335 of the changed_paths2 field. */
336 new_entry->changed_paths = new_entry->changed_paths2;
337
338 return new_entry;
339 }
340
341 svn_location_segment_t *
svn_location_segment_dup(const svn_location_segment_t * segment,apr_pool_t * pool)342 svn_location_segment_dup(const svn_location_segment_t *segment,
343 apr_pool_t *pool)
344 {
345 svn_location_segment_t *new_segment =
346 apr_palloc(pool, sizeof(*new_segment));
347
348 *new_segment = *segment;
349 if (segment->path)
350 new_segment->path = apr_pstrdup(pool, segment->path);
351 return new_segment;
352 }
353