Index: subversion/include/svn_wc.h =================================================================== --- subversion/include/svn_wc.h (revision 17313) +++ subversion/include/svn_wc.h (working copy) @@ -1216,6 +1216,10 @@ typedef struct svn_wc_entry_t * @since New in 1.4. */ svn_boolean_t prop_mods; + /** Cached property existence for this entry. + * @since New in 1.4. */ + const char *has_properties; + /* IMPORTANT: If you extend this structure, check svn_wc_entry_dup() to see if you need to extend that as well. */ } svn_wc_entry_t; Index: subversion/libsvn_wc/props.c =================================================================== --- subversion/libsvn_wc/props.c (revision 17313) +++ subversion/libsvn_wc/props.c (working copy) @@ -299,6 +299,35 @@ svn_wc__get_existing_prop_reject_file (c /*---------------------------------------------------------------------*/ + +char * +svn_wc__build_has_properties (apr_hash_t *props, apr_pool_t *pool) +{ + apr_array_header_t *cached_props; + char *has_properties_string = NULL; + int i; + + if (!props || apr_hash_count (props) == 0) + return ""; + + cached_props = svn_cstring_split (svn_wc__cached_properties (), "|", + TRUE, pool); + for (i = 0; i < cached_props->nelts; i++) + { + const char *proptolookfor = APR_ARRAY_IDX (cached_props, i, + const char *); + + if (apr_hash_get (props, proptolookfor, APR_HASH_KEY_STRING) != NULL) + { + if (!has_properties_string) + has_properties_string = ""; + has_properties_string = apr_pstrcat (pool, has_properties_string, + proptolookfor, "|", NULL); + } + } + return has_properties_string; +} + /*** Installing new properties. ***/ svn_error_t * svn_wc__install_props (svn_stringbuf_t **log_accum, @@ -341,12 +370,15 @@ svn_wc__install_props (svn_stringbuf_t * /* Check if the props are modified. */ SVN_ERR (svn_prop_diffs (&prop_diffs, working_props, base_props, pool)); tmp_entry.prop_mods = (prop_diffs->nelts > 0); + tmp_entry.has_properties = svn_wc__build_has_properties (working_props, + pool); /* ### TODO: Check props in working props and update flags for specific props when we have such flags. */ SVN_ERR (svn_wc__loggy_entry_modify (log_accum, adm_access, name, &tmp_entry, - SVN_WC__ENTRY_MODIFY_PROP_MODS, pool)); + SVN_WC__ENTRY_MODIFY_PROP_MODS + | SVN_WC__ENTRY_MODIFY_HAS_PROPERTIES, pool)); /* Write our property hashes into temporary files. Notice that the paths computed are ABSOLUTE pathnames, which is what our disk @@ -401,6 +433,14 @@ svn_wc__install_props (svn_stringbuf_t * SVN_ERR (svn_wc__loggy_set_readonly (log_accum, adm_access, real_prop_base, pool)); + + memset (&tmp_entry, 0, sizeof (tmp_entry)); + tmp_entry.has_properties = svn_wc__build_has_properties (base_props, + pool); + SVN_ERR (svn_wc__loggy_entry_modify (log_accum, adm_access, name, + &tmp_entry, + SVN_WC__ENTRY_MODIFY_HAS_PROPERTIES, + pool)); } return SVN_NO_ERROR; @@ -1289,9 +1329,32 @@ svn_wc_prop_list (apr_hash_t **props, return svn_wc__load_prop_file (prop_path, *props, pool); } +static svn_boolean_t +svn_is_boolean_property (const char *name) +{ + /* If we end up with more than 3 of these, we should probably put + them in a table and use bsearch. With only three, it doesn't + make any speed difference. */ + if (strcmp (name, SVN_PROP_EXECUTABLE) == 0) + return TRUE; + else if (strcmp (name, SVN_PROP_NEEDS_LOCK) == 0) + return TRUE; + else if (strcmp (name, SVN_PROP_SPECIAL) == 0) + return TRUE; + return FALSE; +} - - +static svn_string_t * +svn_value_of_set_prop (const char *name, apr_pool_t *pool) +{ + if (strcmp (name, SVN_PROP_EXECUTABLE) == 0) + return svn_string_create (SVN_PROP_EXECUTABLE_VALUE, pool); + else if (strcmp (name, SVN_PROP_NEEDS_LOCK) == 0) + return svn_string_create (SVN_PROP_NEEDS_LOCK_VALUE, pool); + else if (strcmp (name, SVN_PROP_SPECIAL) == 0) + return svn_string_create (SVN_PROP_SPECIAL_VALUE, pool); + return NULL; +} svn_error_t * svn_wc_prop_get (const svn_string_t **value, @@ -1304,6 +1367,35 @@ svn_wc_prop_get (const svn_string_t **va apr_hash_t *prophash; enum svn_prop_kind kind = svn_property_kind (NULL, name); + char *tolookfor = apr_pstrcat (pool, name, "|", NULL); + + if (strstr (svn_wc__cached_properties (), tolookfor)) + { + const svn_wc_entry_t *entry; + SVN_ERR (svn_wc_entry (&entry, path, adm_access, TRUE, pool)); + + /* We separate these two cases so that we can return the correct + value for booleans if they exist in the string. */ + if (!entry->has_properties) + { + *value = NULL; + return SVN_NO_ERROR; + } + if (!strstr (entry->has_properties, tolookfor)) + { + *value = NULL; + return SVN_NO_ERROR; + } + if (svn_is_boolean_property (name)) + { + *value = svn_value_of_set_prop (name, pool); + if (*value == NULL) + return svn_error_createf (SVN_ERR_BAD_PROP_KIND, NULL, + _("Boolean property without set value"), + name); + return SVN_NO_ERROR; + } + } if (kind == svn_prop_wc_kind) { @@ -2124,3 +2216,9 @@ svn_wc__has_magic_property (apr_array_he } return FALSE; } + +const char * +svn_wc__cached_properties (void) +{ + return SVN_PROP_SPECIAL "|" SVN_PROP_EXTERNALS "|" SVN_PROP_NEEDS_LOCK "|"; +} Index: subversion/libsvn_wc/props.h =================================================================== --- subversion/libsvn_wc/props.h (revision 17313) +++ subversion/libsvn_wc/props.h (working copy) @@ -159,6 +159,15 @@ svn_error_t *svn_wc__install_props (svn_ svn_boolean_t write_base_props, apr_pool_t *pool); +/* Return a '|' separated string containing the names of all of the + properties that the working copy caches the existence of. */ +const char *svn_wc__cached_properties (void); + +/* Return a '|' separated string containing the names of all cached + properties that are set in PROPS. This string is suitable for + using as the "has_properties" member of the entry structure. */ +char * svn_wc__build_has_properties (apr_hash_t *props, apr_pool_t *pool); + #ifdef __cplusplus } #endif /* __cplusplus */ Index: subversion/libsvn_wc/entries.c =================================================================== --- subversion/libsvn_wc/entries.c (revision 17313) +++ subversion/libsvn_wc/entries.c (working copy) @@ -521,6 +521,14 @@ svn_wc__atts_to_entry (svn_wc_entry_t ** *modify_flags |= SVN_WC__ENTRY_MODIFY_PROP_MODS; } } + + /* has_properties string. */ + + entry->has_properties = apr_hash_get (atts, + SVN_WC__ENTRY_ATTR_HAS_PROPERTIES, + APR_HASH_KEY_STRING); + if (entry->has_properties) + *modify_flags |= SVN_WC__ENTRY_MODIFY_HAS_PROPERTIES; *new_entry = entry; return SVN_NO_ERROR; @@ -1085,6 +1093,11 @@ write_entry (svn_stringbuf_t **output, if (entry->prop_mods) apr_hash_set (atts, SVN_WC__ENTRY_ATTR_PROP_MODS, APR_HASH_KEY_STRING, "true"); + + /* Property existence. */ + if (entry->has_properties) + apr_hash_set (atts, SVN_WC__ENTRY_ATTR_HAS_PROPERTIES, + APR_HASH_KEY_STRING, entry->has_properties); /*** Now, remove stuff that can be derived through inheritance rules. ***/ @@ -1410,6 +1423,12 @@ fold_entry (apr_hash_t *entries, if (modify_flags & SVN_WC__ENTRY_MODIFY_PROP_MODS) cur_entry->prop_mods = entry->prop_mods; + /* Property existence */ + if (modify_flags & SVN_WC__ENTRY_MODIFY_HAS_PROPERTIES) + cur_entry->has_properties = (entry->has_properties + ? apr_pstrdup (pool, entry->has_properties) + : NULL); + /* Absorb defaults from the parent dir, if any, unless this is a subdir entry. */ if (cur_entry->kind != svn_node_dir) @@ -1799,7 +1818,8 @@ svn_wc_entry_dup (const svn_wc_entry_t * dupentry->lock_owner = apr_pstrdup (pool, entry->lock_owner); if (entry->lock_comment) dupentry->lock_comment = apr_pstrdup (pool, entry->lock_comment); - + if (entry->has_properties) + dupentry->has_properties = apr_pstrdup (pool, entry->has_properties); return dupentry; } Index: subversion/libsvn_wc/entries.h =================================================================== --- subversion/libsvn_wc/entries.h (revision 17313) +++ subversion/libsvn_wc/entries.h (working copy) @@ -68,6 +68,7 @@ extern "C" { #define SVN_WC__ENTRY_ATTR_LOCK_COMMENT "lock-comment" #define SVN_WC__ENTRY_ATTR_LOCK_CREATION_DATE "lock-creation-date" #define SVN_WC__ENTRY_ATTR_PROP_MODS "prop-mods" +#define SVN_WC__ENTRY_ATTR_HAS_PROPERTIES "has-properties" /* Attribute values for 'schedule' */ #define SVN_WC__ENTRY_VALUE_ADD "add" @@ -142,6 +143,7 @@ svn_error_t *svn_wc__atts_to_entry (svn_ #define SVN_WC__ENTRY_MODIFY_LOCK_COMMENT 0x01000000 #define SVN_WC__ENTRY_MODIFY_LOCK_CREATION_DATE 0x02000000 #define SVN_WC__ENTRY_MODIFY_PROP_MODS 0x04000000 +#define SVN_WC__ENTRY_MODIFY_HAS_PROPERTIES 0x08000000 /* ...or perhaps this to mean all of those above... */ Index: subversion/libsvn_wc/log.c =================================================================== --- subversion/libsvn_wc/log.c (revision 17313) +++ subversion/libsvn_wc/log.c (working copy) @@ -1943,6 +1943,10 @@ svn_wc__loggy_entry_modify (svn_stringbu SVN_WC__ENTRY_ATTR_PROP_MODS, entry->prop_mods ? "true" : "false"); + ADD_ENTRY_ATTR (SVN_WC__ENTRY_MODIFY_HAS_PROPERTIES, + SVN_WC__ENTRY_ATTR_HAS_PROPERTIES, + entry->has_properties); + #undef ADD_ENTRY_ATTR return svn_wc__loggy_entry_modify_hash (log_accum, adm_access, name, Index: subversion/libsvn_wc/adm_ops.c =================================================================== --- subversion/libsvn_wc/adm_ops.c (revision 17313) +++ subversion/libsvn_wc/adm_ops.c (working copy) @@ -1347,6 +1347,7 @@ revert_admin_things (svn_wc_adm_access_t svn_boolean_t modified_p, tgt_modified; svn_boolean_t target_needs_retranslation = FALSE; apr_hash_t *modify_entry_atts = apr_hash_make (pool); + apr_hash_t *props; svn_stringbuf_t *log_accum = svn_stringbuf_create ("", pool); const char *bprop, *rprop, *wprop; /* full paths */ const char *adm_path = svn_wc_adm_access_path (adm_access); @@ -1397,6 +1398,11 @@ revert_admin_things (svn_wc_adm_access_t apr_hash_set (modify_entry_atts, SVN_WC__ENTRY_ATTR_PROP_MODS, APR_HASH_KEY_STRING, "false"); + props = apr_hash_make (pool); + SVN_ERR (svn_wc__load_prop_file (rprop, props, pool)); + apr_hash_set (modify_entry_atts, SVN_WC__ENTRY_ATTR_HAS_PROPERTIES, + APR_HASH_KEY_STRING, + svn_wc__build_has_properties (props, pool)); /* ### TODO: Update properties flags when we have such flags. */ } else if (entry->schedule == svn_wc_schedule_replace) Index: subversion/libsvn_wc/translate.c =================================================================== --- subversion/libsvn_wc/translate.c (revision 17313) +++ subversion/libsvn_wc/translate.c (working copy) @@ -218,17 +218,13 @@ svn_wc__get_special (svn_boolean_t *spec svn_wc_adm_access_t *adm_access, apr_pool_t *pool) { - apr_hash_t *prophash; + const svn_string_t *propval; svn_error_t *err; - + /* Get the property value. */ - err = svn_wc_prop_list (&prophash, path, adm_access, pool); - if (err) - return - svn_error_quick_wrap - (err, _("Failed to load properties from disk")); - - *special = svn_wc__has_special_property (prophash); + SVN_ERR (svn_wc_prop_get (&propval, SVN_PROP_SPECIAL, path, + adm_access, pool)); + *special = propval != NULL; return SVN_NO_ERROR; }