2 * properties.c: stuff related to Subversion properties
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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
21 * ====================================================================
26 #include <apr_pools.h>
28 #include <apr_tables.h>
29 #include <string.h> /* for strncmp() */
31 #include "svn_string.h"
32 #include "svn_props.h"
33 #include "svn_error.h"
34 #include "svn_ctype.h"
35 #include "private/svn_subr_private.h"
38 /* All Subversion-specific versioned node properties
39 * known to this client, that are applicable to both a file and a dir.
41 #define SVN_PROP__NODE_COMMON_PROPS SVN_PROP_MERGEINFO, \
47 /* All Subversion-specific versioned node properties
48 * known to this client, that are applicable to a dir only.
50 #define SVN_PROP__NODE_DIR_ONLY_PROPS SVN_PROP_IGNORE, \
51 SVN_PROP_INHERITABLE_IGNORES, \
52 SVN_PROP_INHERITABLE_AUTO_PROPS, \
55 /* All Subversion-specific versioned node properties
56 * known to this client, that are applicable to a file only.
58 #define SVN_PROP__NODE_FILE_ONLY_PROPS SVN_PROP_MIME_TYPE, \
61 SVN_PROP_EXECUTABLE, \
62 SVN_PROP_NEEDS_LOCK, \
65 static const char *const known_rev_props
[]
66 = { SVN_PROP_REVISION_ALL_PROPS
69 static const char *const known_node_props
[]
70 = { SVN_PROP__NODE_COMMON_PROPS
71 SVN_PROP__NODE_DIR_ONLY_PROPS
72 SVN_PROP__NODE_FILE_ONLY_PROPS
75 static const char *const known_dir_props
[]
76 = { SVN_PROP__NODE_COMMON_PROPS
77 SVN_PROP__NODE_DIR_ONLY_PROPS
80 static const char *const known_file_props
[]
81 = { SVN_PROP__NODE_COMMON_PROPS
82 SVN_PROP__NODE_FILE_ONLY_PROPS
86 is_known_prop(const char *prop_name
,
87 const char *const *known_props
)
91 if (strcmp(prop_name
, *known_props
++) == 0)
98 svn_prop_is_known_svn_rev_prop(const char *prop_name
)
100 return is_known_prop(prop_name
, known_rev_props
);
104 svn_prop_is_known_svn_node_prop(const char *prop_name
)
106 return is_known_prop(prop_name
, known_node_props
);
110 svn_prop_is_known_svn_file_prop(const char *prop_name
)
112 return is_known_prop(prop_name
, known_file_props
);
116 svn_prop_is_known_svn_dir_prop(const char *prop_name
)
118 return is_known_prop(prop_name
, known_dir_props
);
123 svn_prop_is_svn_prop(const char *prop_name
)
125 return strncmp(prop_name
, SVN_PROP_PREFIX
, (sizeof(SVN_PROP_PREFIX
) - 1))
131 svn_prop_has_svn_prop(const apr_hash_t
*props
, apr_pool_t
*pool
)
133 apr_hash_index_t
*hi
;
134 const void *prop_name
;
139 for (hi
= apr_hash_first(pool
, (apr_hash_t
*)props
); hi
;
140 hi
= apr_hash_next(hi
))
142 apr_hash_this(hi
, &prop_name
, NULL
, NULL
);
143 if (svn_prop_is_svn_prop((const char *) prop_name
))
151 #define SIZEOF_WC_PREFIX (sizeof(SVN_PROP_WC_PREFIX) - 1)
152 #define SIZEOF_ENTRY_PREFIX (sizeof(SVN_PROP_ENTRY_PREFIX) - 1)
155 svn_property_kind2(const char *prop_name
)
158 if (strncmp(prop_name
, SVN_PROP_WC_PREFIX
, SIZEOF_WC_PREFIX
) == 0)
159 return svn_prop_wc_kind
;
161 if (strncmp(prop_name
, SVN_PROP_ENTRY_PREFIX
, SIZEOF_ENTRY_PREFIX
) == 0)
162 return svn_prop_entry_kind
;
164 return svn_prop_regular_kind
;
168 /* NOTE: this function is deprecated, but we cannot move it to deprecated.c
169 because we need the SIZEOF_*_PREFIX constant symbols defined above. */
171 svn_property_kind(int *prefix_len
,
172 const char *prop_name
)
174 svn_prop_kind_t kind
= svn_property_kind2(prop_name
);
178 if (kind
== svn_prop_wc_kind
)
179 *prefix_len
= SIZEOF_WC_PREFIX
;
180 else if (kind
== svn_prop_entry_kind
)
181 *prefix_len
= SIZEOF_ENTRY_PREFIX
;
191 svn_categorize_props(const apr_array_header_t
*proplist
,
192 apr_array_header_t
**entry_props
,
193 apr_array_header_t
**wc_props
,
194 apr_array_header_t
**regular_props
,
199 *entry_props
= apr_array_make(pool
, 1, sizeof(svn_prop_t
));
201 *wc_props
= apr_array_make(pool
, 1, sizeof(svn_prop_t
));
203 *regular_props
= apr_array_make(pool
, 1, sizeof(svn_prop_t
));
205 for (i
= 0; i
< proplist
->nelts
; i
++)
207 svn_prop_t
*prop
, *newprop
;
208 enum svn_prop_kind kind
;
210 prop
= &APR_ARRAY_IDX(proplist
, i
, svn_prop_t
);
211 kind
= svn_property_kind2(prop
->name
);
214 if (kind
== svn_prop_regular_kind
)
217 newprop
= apr_array_push(*regular_props
);
219 else if (kind
== svn_prop_wc_kind
)
222 newprop
= apr_array_push(*wc_props
);
224 else if (kind
== svn_prop_entry_kind
)
227 newprop
= apr_array_push(*entry_props
);
230 /* Technically this can't happen, but might as well have the
231 code ready in case that ever changes. */
232 return svn_error_createf(SVN_ERR_BAD_PROP_KIND
, NULL
,
233 "Bad property kind for property '%s'",
238 newprop
->name
= prop
->name
;
239 newprop
->value
= prop
->value
;
248 svn_prop_diffs(apr_array_header_t
**propdiffs
,
249 const apr_hash_t
*target_props
,
250 const apr_hash_t
*source_props
,
253 apr_hash_index_t
*hi
;
254 apr_array_header_t
*ary
= apr_array_make(pool
, 1, sizeof(svn_prop_t
));
256 /* Note: we will be storing the pointers to the keys (from the hashes)
257 into the propdiffs array. It is acceptable for us to
258 reference the same memory as the base/target_props hash. */
260 /* Loop over SOURCE_PROPS and examine each key. This will allow us to
261 detect any `deletion' events or `set-modification' events. */
262 for (hi
= apr_hash_first(pool
, (apr_hash_t
*)source_props
); hi
;
263 hi
= apr_hash_next(hi
))
268 const svn_string_t
*propval1
, *propval2
;
270 /* Get next property */
271 apr_hash_this(hi
, &key
, &klen
, &val
);
274 /* Does property name exist in TARGET_PROPS? */
275 propval2
= apr_hash_get((apr_hash_t
*)target_props
, key
, klen
);
277 if (propval2
== NULL
)
279 /* Add a delete event to the array */
280 svn_prop_t
*p
= apr_array_push(ary
);
284 else if (! svn_string_compare(propval1
, propval2
))
286 /* Add a set (modification) event to the array */
287 svn_prop_t
*p
= apr_array_push(ary
);
289 p
->value
= svn_string_dup(propval2
, pool
);
293 /* Loop over TARGET_PROPS and examine each key. This allows us to
294 detect `set-creation' events */
295 for (hi
= apr_hash_first(pool
, (apr_hash_t
*)target_props
); hi
;
296 hi
= apr_hash_next(hi
))
301 const svn_string_t
*propval
;
303 /* Get next property */
304 apr_hash_this(hi
, &key
, &klen
, &val
);
307 /* Does property name exist in SOURCE_PROPS? */
308 if (NULL
== apr_hash_get((apr_hash_t
*)source_props
, key
, klen
))
310 /* Add a set (creation) event to the array */
311 svn_prop_t
*p
= apr_array_push(ary
);
313 p
->value
= svn_string_dup(propval
, pool
);
317 /* Done building our array of user events. */
324 svn_prop__patch(const apr_hash_t
*original_props
,
325 const apr_array_header_t
*prop_changes
,
328 apr_hash_t
*props
= apr_hash_copy(pool
, original_props
);
331 for (i
= 0; i
< prop_changes
->nelts
; i
++)
333 const svn_prop_t
*p
= &APR_ARRAY_IDX(prop_changes
, i
, svn_prop_t
);
335 svn_hash_sets(props
, p
->name
, p
->value
);
341 * Reallocate the members of PROP using POOL.
344 svn_prop__members_dup(svn_prop_t
*prop
, apr_pool_t
*pool
)
347 prop
->name
= apr_pstrdup(pool
, prop
->name
);
349 prop
->value
= svn_string_dup(prop
->value
, pool
);
353 svn_prop_dup(const svn_prop_t
*prop
, apr_pool_t
*pool
)
355 svn_prop_t
*new_prop
= apr_palloc(pool
, sizeof(*new_prop
));
359 svn_prop__members_dup(new_prop
, pool
);
365 svn_prop_array_dup(const apr_array_header_t
*array
, apr_pool_t
*pool
)
368 apr_array_header_t
*new_array
= apr_array_copy(pool
, array
);
369 for (i
= 0; i
< new_array
->nelts
; ++i
)
371 svn_prop_t
*elt
= &APR_ARRAY_IDX(new_array
, i
, svn_prop_t
);
372 svn_prop__members_dup(elt
, pool
);
378 svn_prop_hash_to_array(const apr_hash_t
*hash
,
381 apr_hash_index_t
*hi
;
382 apr_array_header_t
*array
= apr_array_make(pool
,
383 apr_hash_count((apr_hash_t
*)hash
),
386 for (hi
= apr_hash_first(pool
, (apr_hash_t
*)hash
); hi
;
387 hi
= apr_hash_next(hi
))
393 apr_hash_this(hi
, &key
, NULL
, &val
);
396 APR_ARRAY_PUSH(array
, svn_prop_t
) = prop
;
403 svn_prop_hash_dup(const apr_hash_t
*hash
,
406 apr_hash_index_t
*hi
;
407 apr_hash_t
*new_hash
= apr_hash_make(pool
);
409 for (hi
= apr_hash_first(pool
, (apr_hash_t
*)hash
); hi
;
410 hi
= apr_hash_next(hi
))
416 apr_hash_this(hi
, &key
, &klen
, &prop
);
417 apr_hash_set(new_hash
, apr_pstrmemdup(pool
, key
, klen
), klen
,
418 svn_string_dup(prop
, pool
));
424 svn_prop_array_to_hash(const apr_array_header_t
*properties
,
428 apr_hash_t
*prop_hash
= apr_hash_make(pool
);
430 for (i
= 0; i
< properties
->nelts
; i
++)
432 const svn_prop_t
*prop
= &APR_ARRAY_IDX(properties
, i
, svn_prop_t
);
433 svn_hash_sets(prop_hash
, prop
->name
, prop
->value
);
440 svn_prop_is_boolean(const char *prop_name
)
442 /* If we end up with more than 3 of these, we should probably put
443 them in a table and use bsearch. With only three, it doesn't
444 make any speed difference. */
445 if (strcmp(prop_name
, SVN_PROP_EXECUTABLE
) == 0
446 || strcmp(prop_name
, SVN_PROP_NEEDS_LOCK
) == 0
447 || strcmp(prop_name
, SVN_PROP_SPECIAL
) == 0)
454 svn_prop_needs_translation(const char *propname
)
456 /* ### Someday, we may want to be picky and choosy about which
457 properties require UTF8 and EOL conversion. For now, all "svn:"
460 return svn_prop_is_svn_prop(propname
);
465 svn_prop_name_is_valid(const char *prop_name
)
467 const char *p
= prop_name
;
469 /* The characters we allow use identical representations in UTF8
470 and ASCII, so we can just test for the appropriate ASCII codes.
471 But we can't use standard C character notation ('A', 'B', etc)
472 because there's no guarantee that this C environment is using
475 if (!(svn_ctype_isalpha(*p
)
476 || *p
== SVN_CTYPE_ASCII_COLON
477 || *p
== SVN_CTYPE_ASCII_UNDERSCORE
))
482 if (!(svn_ctype_isalnum(*p
)
483 || *p
== SVN_CTYPE_ASCII_MINUS
484 || *p
== SVN_CTYPE_ASCII_DOT
485 || *p
== SVN_CTYPE_ASCII_COLON
486 || *p
== SVN_CTYPE_ASCII_UNDERSCORE
))
493 svn_prop_get_value(const apr_hash_t
*props
,
494 const char *prop_name
)
501 str
= svn_hash_gets((apr_hash_t
*)props
, prop_name
);