You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2014/02/02 03:23:32 UTC
svn commit: r1563542 - in /subversion/branches/fsfs-ucsnorm/subversion:
include/svn_error_codes.h libsvn_fs_fs/temp_serializer.c
Author: brane
Date: Sun Feb 2 02:23:30 2014
New Revision: 1563542
URL: http://svn.apache.org/r1563542
Log:
On the fsfs-ucsnorm branch: Prevent modifications of nodes with paths
that contain name collisions.
* subversion/include/svn_error_codes.h
(SVN_ERR_FS_NAME_COLLISION): New error code.
* subversion/libsvn_fs_fs/temp_serializer.c
(get_entry_key): New; factored entry key deserialization from find_entry.
(find_entry): Changed signature to return an svn_error_t*.
Call get_entry_key instead of duplicating the deserialization in three
(formerly two) places.
If the entry was found, double-check that its key is unique.
(svn_fs_fs__extract_dir_entry, svn_fs_fs__replace_dir_entry):
Update calls to find_entry.
Modified:
subversion/branches/fsfs-ucsnorm/subversion/include/svn_error_codes.h
subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/temp_serializer.c
Modified: subversion/branches/fsfs-ucsnorm/subversion/include/svn_error_codes.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/include/svn_error_codes.h?rev=1563542&r1=1563541&r2=1563542&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/include/svn_error_codes.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/include/svn_error_codes.h Sun Feb 2 02:23:30 2014
@@ -846,6 +846,11 @@ SVN_ERROR_START
SVN_ERR_FS_CATEGORY_START + 60,
"Move without a suitable deletion")
+ /** @since New in 1.9. */
+ SVN_ERRDEF(SVN_ERR_FS_NAME_COLLISION,
+ SVN_ERR_FS_CATEGORY_START + 61,
+ "Normalized directory entry names are identical")
+
/* repos errors */
SVN_ERRDEF(SVN_ERR_REPOS_LOCKED,
Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/temp_serializer.c?rev=1563542&r1=1563541&r2=1563542&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/temp_serializer.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/temp_serializer.c Sun Feb 2 02:23:30 2014
@@ -767,13 +767,30 @@ svn_fs_fs__get_sharded_offset(void **out
return SVN_NO_ERROR;
}
-/* Utility function that returns the lowest index of the first entry in
- * *ENTRIES that points to a dir entry with a key equal or larger than KEY.
- * If an exact match has been found, *FOUND will be set to TRUE. COUNT is
- * the number of valid entries in ENTRIES.
+/* Helper function for find_entry() that returns the key for ENTRIES[INDEX] */
+static const char *
+get_entry_key(svn_fs_fs__dirent_t **entries, apr_size_t index)
+{
+ const svn_fs_fs__dirent_t *entry =
+ svn_temp_deserializer__ptr(entries, (const void *const *)&entries[index]);
+ const char* entry_key =
+ svn_temp_deserializer__ptr(entry, (const void *const *)&entry->key);
+
+ /* use the name if it's identical to the key */
+ if (!entry_key)
+ entry_key = svn_temp_deserializer__ptr(
+ entry, (const void *const *)&entry->dirent.name);
+ return entry_key;
+}
+
+/* Utility function that sets *POSITION to the lowest index of the
+ * first entry in *ENTRIES that points to a dir entry with a key equal
+ * or larger than KEY. If an exact match has been found, *FOUND will
+ * be set to TRUE. COUNT is the number of valid entries in ENTRIES.
*/
-static apr_size_t
-find_entry(svn_fs_fs__dirent_t **entries,
+static svn_error_t *
+find_entry(apr_size_t *position,
+ svn_fs_fs__dirent_t **entries,
const char *key,
apr_size_t count,
svn_boolean_t *found)
@@ -785,15 +802,7 @@ find_entry(svn_fs_fs__dirent_t **entries
for (middle = upper / 2; lower < upper; middle = (upper + lower) / 2)
{
- const svn_fs_fs__dirent_t *entry =
- svn_temp_deserializer__ptr(entries, (const void *const *)&entries[middle]);
- const char* entry_key =
- svn_temp_deserializer__ptr(entry, (const void *const *)&entry->key);
-
- /* use the name if it's identical to the key */
- if (!entry_key)
- entry_key = svn_temp_deserializer__ptr(
- entry, (const void *const *)&entry->dirent.name);
+ const char *entry_key = get_entry_key(entries, middle);
if (0 >= strcmp(entry_key, key))
lower = middle + 1;
@@ -805,20 +814,40 @@ find_entry(svn_fs_fs__dirent_t **entries
*found = FALSE;
if (lower < count)
{
- const svn_fs_fs__dirent_t *entry =
- svn_temp_deserializer__ptr(entries, (const void *const *)&entries[lower]);
- const char* entry_key =
- svn_temp_deserializer__ptr(entry, (const void *const *)&entry->key);
+ const char *entry_key = get_entry_key(entries, lower);
+
+ if (0 == strcmp(entry_key, key))
+ {
+ *found = TRUE;
- /* use the name if it's identical to the key */
- if (!entry_key)
- entry_key = svn_temp_deserializer__ptr(
- entry, (const void *const *)&entry->dirent.name);
+ /* Check for name collisions in the directory list.
- *found = (strcmp(entry_key, key) == 0);
+ A repository that was upgraded from FSFS v6 or earlier
+ and had not been properly verified and sanitized might
+ contain name collisions. When normalized lookups are
+ enabled, we must forbid all operations on colliding
+ names, or users might end up making modifications to the
+ wrong node.
+
+ XXX This check is really only needed when normalized
+ lookups are enabled. If it turns out to be a
+ performance problem, we can propagate the
+ normalized-lookups flag all the way through the API
+ to here. */
+ if (/* normalized_lookup && */ count > 1 && lower < count - 1)
+ {
+ entry_key = get_entry_key(entries, lower + 1);
+ if (0 == strcmp(entry_key, key))
+ return svn_error_createf(
+ SVN_ERR_FS_NAME_COLLISION, NULL,
+ _("A directory contains more than one entry named '%s'"),
+ key);
+ }
+ }
}
- return lower;
+ *position = lower;
+ return SVN_NO_ERROR;
}
svn_error_t *
@@ -841,10 +870,9 @@ svn_fs_fs__extract_dir_entry(void **out,
svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->lengths);
/* binary search for the desired entry by key */
- apr_size_t pos = find_entry((svn_fs_fs__dirent_t **)entries,
- key,
- dir_data->count,
- &found);
+ apr_size_t pos;
+ SVN_ERR(find_entry(&pos, (svn_fs_fs__dirent_t **)entries,
+ key, dir_data->count, &found));
/* de-serialize that entry or return NULL, if no match has been found */
*out = NULL;
@@ -954,7 +982,8 @@ svn_fs_fs__replace_dir_entry(void **data
(const void *const *)&dir_data->lengths);
/* binary search for the desired entry by key */
- pos = find_entry(entries, replace_baton->key, dir_data->count, &found);
+ SVN_ERR(find_entry(&pos, entries, replace_baton->key,
+ dir_data->count, &found));
/* handle entry removal (if found at all) */
if (replace_baton->new_entry == NULL)