Index: subversion/include/svn_wc.h =================================================================== --- subversion/include/svn_wc.h (revision 17287) +++ 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; @@ -3244,6 +3248,12 @@ svn_error_t *svn_wc_remove_lock (const c svn_wc_adm_access_t *adm_access, apr_pool_t *pool); +/** Return a comma separated string containing the names of all of the + * properties that the working copy caches the existence of. + * @since New in 1.4. + */ +const char *svn_wc_cached_properties (void); + #ifdef __cplusplus } Index: subversion/libsvn_wc/props.c =================================================================== --- subversion/libsvn_wc/props.c (revision 17287) +++ subversion/libsvn_wc/props.c (working copy) @@ -314,9 +314,12 @@ svn_wc__install_props (svn_stringbuf_t * const char *full_path; const char *access_path = svn_wc_adm_access_path (adm_access); int access_len = strlen (access_path); + apr_array_header_t *cached_props; apr_array_header_t *prop_diffs; svn_wc_entry_t tmp_entry; svn_node_kind_t kind; + char *has_properties_string = NULL; + int i; /* Non-empty path without trailing slash need an extra slash removed */ if (access_len != 0 && access_path[access_len - 1] != '/') @@ -342,11 +345,32 @@ svn_wc__install_props (svn_stringbuf_t * SVN_ERR (svn_prop_diffs (&prop_diffs, working_props, base_props, pool)); tmp_entry.prop_mods = (prop_diffs->nelts > 0); + + + 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 (working_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); + } + } + + tmp_entry.has_properties = has_properties_string; + /* ### 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 +425,26 @@ svn_wc__install_props (svn_stringbuf_t * SVN_ERR (svn_wc__loggy_set_readonly (log_accum, adm_access, real_prop_base, pool)); + has_properties_string = NULL; + for (i = 0; i < cached_props->nelts; i++) + { + const char *proptolookfor = APR_ARRAY_IDX (cached_props, i, const char *); + if (apr_hash_get (base_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); + } + } + memset (&tmp_entry, 0, sizeof (tmp_entry)); + tmp_entry.has_properties = has_properties_string; + + /* ### 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_HAS_PROPERTIES, pool)); } return SVN_NO_ERROR; @@ -1302,9 +1346,19 @@ svn_wc_prop_get (const svn_string_t **va { svn_error_t *err; apr_hash_t *prophash; - enum svn_prop_kind kind = svn_property_kind (NULL, name); + if (strstr (svn_wc_cached_properties (), name)) + { + const svn_wc_entry_t *entry; + SVN_ERR (svn_wc_entry (&entry, path, adm_access, TRUE, pool)); + if (!entry->has_properties || !strstr (entry->has_properties, name)) + { + *value = NULL; + return SVN_NO_ERROR; + } + } + if (kind == svn_prop_wc_kind) { return svn_wc__wcprop_get (value, name, path, adm_access, pool); @@ -2147,3 +2201,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/entries.c =================================================================== --- subversion/libsvn_wc/entries.c (revision 17287) +++ 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 17287) +++ 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 17287) +++ subversion/libsvn_wc/log.c (working copy) @@ -1969,6 +1969,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,