summaryrefslogtreecommitdiff
path: root/subversion/libsvn_fs_util/fs-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_fs_util/fs-util.c')
-rw-r--r--subversion/libsvn_fs_util/fs-util.c62
1 files changed, 56 insertions, 6 deletions
diff --git a/subversion/libsvn_fs_util/fs-util.c b/subversion/libsvn_fs_util/fs-util.c
index 682f43d..da57bc9 100644
--- a/subversion/libsvn_fs_util/fs-util.c
+++ b/subversion/libsvn_fs_util/fs-util.c
@@ -26,6 +26,7 @@
#include <apr_pools.h>
#include <apr_strings.h>
+#include "svn_hash.h"
#include "svn_fs.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
@@ -35,6 +36,48 @@
#include "private/svn_fspath.h"
#include "../libsvn_fs/fs-loader.h"
+/* Return TRUE, if PATH of PATH_LEN > 0 chars starts with a '/' and does
+ * not end with a '/' and does not contain duplicate '/'.
+ */
+static svn_boolean_t
+is_canonical_abspath(const char *path, size_t path_len)
+{
+ const char *end;
+
+ /* check for leading '/' */
+ if (path[0] != '/')
+ return FALSE;
+
+ /* check for trailing '/' */
+ if (path_len == 1)
+ return TRUE;
+ if (path[path_len - 1] == '/')
+ return FALSE;
+
+ /* check for "//" */
+ end = path + path_len - 1;
+ for (; path != end; ++path)
+ if ((path[0] == '/') && (path[1] == '/'))
+ return FALSE;
+
+ return TRUE;
+}
+
+svn_boolean_t
+svn_fs__is_canonical_abspath(const char *path)
+{
+ /* No PATH? No problem. */
+ if (! path)
+ return TRUE;
+
+ /* Empty PATH? That's just "/". */
+ if (! *path)
+ return FALSE;
+
+ /* detailed checks */
+ return is_canonical_abspath(path, strlen(path));
+}
+
const char *
svn_fs__canonicalize_abspath(const char *path, apr_pool_t *pool)
{
@@ -49,12 +92,16 @@ svn_fs__canonicalize_abspath(const char *path, apr_pool_t *pool)
/* Empty PATH? That's just "/". */
if (! *path)
- return apr_pstrdup(pool, "/");
+ return "/";
+
+ /* Non-trivial cases. Maybe, the path already is canonical after all? */
+ path_len = strlen(path);
+ if (is_canonical_abspath(path, path_len))
+ return apr_pstrmemdup(pool, path, path_len);
/* Now, the fun begins. Alloc enough room to hold PATH with an
added leading '/'. */
- path_len = strlen(path);
- newpath = apr_pcalloc(pool, path_len + 2);
+ newpath = apr_palloc(pool, path_len + 2);
/* No leading slash? Fix that. */
if (*path != '/')
@@ -89,6 +136,8 @@ svn_fs__canonicalize_abspath(const char *path, apr_pool_t *pool)
the root directory case)? */
if ((newpath[newpath_i - 1] == '/') && (newpath_i > 1))
newpath[newpath_i - 1] = '\0';
+ else
+ newpath[newpath_i] = '\0';
return newpath;
}
@@ -163,10 +212,11 @@ svn_fs__append_to_merged_froms(svn_mergeinfo_t *output,
for (hi = apr_hash_first(pool, input); hi; hi = apr_hash_next(hi))
{
const char *path = svn__apr_hash_index_key(hi);
- apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+ svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
- apr_hash_set(*output, svn_fspath__join(path, rel_path, pool),
- APR_HASH_KEY_STRING, svn_rangelist_dup(rangelist, pool));
+ svn_hash_sets(*output,
+ svn_fspath__join(path, rel_path, pool),
+ svn_rangelist_dup(rangelist, pool));
}
return SVN_NO_ERROR;