diff options
Diffstat (limited to 'subversion/libsvn_fs_util/fs-util.c')
-rw-r--r-- | subversion/libsvn_fs_util/fs-util.c | 62 |
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; |