Index: subversion/include/svn_path.h =================================================================== --- subversion/include/svn_path.h (revision 18872) +++ subversion/include/svn_path.h (working copy) @@ -185,6 +185,9 @@ * separator characters, and possibly other semantically inoperative * transformations. * + * If the URL contains a hostname, convert that to lowercase to support + * case-insensitive handling of hostnames ( see issue 2475 ) + * * The returned path may be statically allocated, equal to @a path, or * allocated from @a pool. */ Index: subversion/libsvn_subr/path.c =================================================================== --- subversion/libsvn_subr/path.c (revision 18872) +++ subversion/libsvn_subr/path.c (working copy) @@ -23,6 +23,7 @@ #include #include +#include #include "svn_string.h" #include "svn_path.h" @@ -1139,6 +1140,25 @@ } + if (uri) + { + // convert hostname to lowercase + apr_uri_t host_uri; + apr_size_t offset; + int i; + + apr_uri_parse(pool, path, &host_uri); + + for(i = 0; host_uri.hostname[i]; i++) + host_uri.hostname[i] = tolower(host_uri.hostname[i]); + + // path will be pointing to a new memory location, so update src to + // point to the new location too. + offset = src - path; + path = apr_uri_unparse(pool, &host_uri, APR_URI_UNP_REVEALPASSWORD); + src = path + offset; + } + while (*src) { /* Parse each segment, find the closing '/' */ Index: subversion/libsvn_wc/entries.c =================================================================== --- subversion/libsvn_wc/entries.c (revision 18872) +++ subversion/libsvn_wc/entries.c (working copy) @@ -240,9 +240,12 @@ { entry->url = apr_hash_get(atts, SVN_WC__ENTRY_ATTR_URL, APR_HASH_KEY_STRING); - - if (entry->url) - *modify_flags |= SVN_WC__ENTRY_MODIFY_URL; + + if (entry->url) + { + *modify_flags |= SVN_WC__ENTRY_MODIFY_URL; + entry->url = svn_path_canonicalize(entry->url, pool); + } } /* Set up repository root. Make sure it is a prefix of url. */ @@ -251,6 +254,7 @@ APR_HASH_KEY_STRING); if (entry->repos) { + entry->repos = svn_path_canonicalize(entry->repos, pool); if (entry->url && ! svn_path_is_ancestor(entry->repos, entry->url)) return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, _("Entry for '%s' has invalid repository " Index: subversion/tests/cmdline/path_tests.py =================================================================== --- subversion/tests/cmdline/path_tests.py (revision 0) +++ subversion/tests/cmdline/path_tests.py (revision 0) @@ -0,0 +1,187 @@ +#!/usr/bin/env python +# +# path_tests.py: testing case insensitive hostname handling. +# +# Subversion is a tool for revision control. +# See http://subversion.tigris.org for more information. +# +# ==================================================================== +# Copyright (c) 2000-2006 CollabNet. All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://subversion.tigris.org/license-1.html. +# If newer versions of this license are posted there, you may use a +# newer version instead, at your option. +# +###################################################################### + +# General modules +import os +from urlparse import urlparse, urlunparse +from string import lower, upper + +# Our testing module +import svntest + +import re + +###################################################################### +# Utilities +# + +def change_case_of_hostname(input): + "Change the case of the hostname, try uppercase first" + + m = re.match(r"^(.*://)([^/]*)(.*)", input) + if m: + scheme = m.group(1) + host = upper(m.group(2)) + if host == m.group(2): + host = lower(m.group(2)) + + path = m.group(3) + + return scheme + host + path + +###################################################################### +# Tests +# +# Each test must return on success or raise on failure. + + +#---------------------------------------------------------------------- + +# regression test for issue #2475 - move file and folder +def path_move_between_wcs(sbox): + "case issue #2475 - move file and folder" + sbox.build() + + # checkout a second working copy, use repository url with different case + wc_dir2 = sbox.wc_dir + '2' + repo_url2 = change_case_of_hostname(svntest.main.current_repo_url) + + # Generate the expected output tree. + expected_output = svntest.main.greek_state.copy() + expected_output.wc_dir = wc_dir2 + expected_output.tweak(status='A ', contents=None) + + # Generate an expected wc tree. + expected_wc = svntest.main.greek_state + + # Do a checkout, and verify the resulting output and disk contents. + svntest.actions.run_and_verify_checkout(repo_url2, + wc_dir2, + expected_output, + expected_wc) + + # Move a file from wc to wc2 + mu_path = os.path.join(sbox.wc_dir, 'A', 'mu') + E_path = os.path.join(wc_dir2, 'A', 'B', 'E') + + svntest.main.run_svn(None, 'mv', mu_path, E_path) + + # Move a folder from wc to wc2 + E_path = os.path.join(sbox.wc_dir, 'A', 'B', 'E') + A_path = os.path.join(wc_dir2, 'A') + + svntest.main.run_svn(None, 'mv', E_path, A_path) + +# regression test for issue #2475 - move file and folder +def path_copy_between_wcs(sbox): + "case issue #2475 - copy file and folder" + sbox.build() + + # checkout a second working copy, use repository url with different case + wc_dir2 = sbox.wc_dir + '2' + repo_url2 = change_case_of_hostname(svntest.main.current_repo_url) + + # Generate the expected output tree. + expected_output = svntest.main.greek_state.copy() + expected_output.wc_dir = wc_dir2 + expected_output.tweak(status='A ', contents=None) + + # Generate an expected wc tree. + expected_wc = svntest.main.greek_state + + # Do a checkout, and verify the resulting output and disk contents. + svntest.actions.run_and_verify_checkout(repo_url2, + wc_dir2, + expected_output, + expected_wc) + + # Copy a file from wc to wc2 + mu_path = os.path.join(sbox.wc_dir, 'A', 'mu') + E_path = os.path.join(wc_dir2, 'A', 'B', 'E') + + svntest.main.run_svn(None, 'cp', mu_path, E_path) + + # Copy a folder from wc to wc2 + E_path = os.path.join(sbox.wc_dir, 'A', 'B', 'E') + A_path = os.path.join(wc_dir2, 'A') + + svntest.main.run_svn(None, 'cp', E_path, A_path) + +# regression test for issue #2475 - direct copy in the repository +# this test handles the 'direct move' case too, that uses the same code. +def path_copy_in_repo(sbox): + "case issue #2475 - direct copy in the repository" + sbox.build() + + repo_url2 = change_case_of_hostname(svntest.main.current_repo_url) + + # Copy a file from repo to repo2 + mu_url = svntest.main.current_repo_url + '/A/mu' + E_url = repo_url2 + '/A/B/E' + + svntest.main.run_svn(None, 'cp', mu_url, E_url, '-m', 'copy mu to /A/B/E') + +# regression test for issue #2475 - checkout in a working copy +def path_checkout(sbox): + "case issue #2475 - checkout in wc" + sbox.build() + + # checkout a working copy non-recursively + wc_dir2 = sbox.wc_dir + '2' + + output, errput = svntest.main.run_svn (None, 'co', + '--username', svntest.main.wc_author, + '--password', svntest.main.wc_passwd, + '-N', + svntest.main.current_repo_url, wc_dir2) + + # checkout in the same working copy, use repository url with different case + repo_url2 = change_case_of_hostname(svntest.main.current_repo_url) + + # Generate the expected output tree. + expected_output = svntest.main.greek_state.copy() + expected_output.wc_dir = wc_dir2 + expected_output.tweak(status='A ', contents=None) + + # Generate an expected wc tree. + expected_wc = svntest.main.greek_state + + # Do a checkout, and verify the resulting output and disk contents. + svntest.actions.run_and_verify_checkout(repo_url2, + wc_dir2, + expected_output, + expected_wc) + +######################################################################## +# Run the tests + + +# list all tests here, starting with None: +test_list = [ None, + path_move_between_wcs, + path_copy_between_wcs, + path_copy_in_repo, + path_checkout + ] + +if __name__ == '__main__': + svntest.main.run_tests(test_list) + # NOTREACHED + + +### End of file. Index: subversion/tests/libsvn_subr/path-test.c =================================================================== --- subversion/tests/libsvn_subr/path-test.c (revision 18872) +++ subversion/tests/libsvn_subr/path-test.c (working copy) @@ -670,6 +670,11 @@ { "http://hst", "http://hst" }, { "http://hst/foo/../bar","http://hst/foo/../bar" }, { "http://hst/", "http://hst" }, + { "http://HST/", "http://hst" }, + { "http://HST/FOO/BaR", "http://hst/FOO/BaR" }, + { "svn+ssh://j.random@HST/HST/FOO/BaR", "svn+ssh://j.random@hst/HST/FOO/BaR" }, + { "svn+ssh://j.random:jray@HST/HST/FOO/BaR", "svn+ssh://j.random:jray@hst/HST/FOO/BaR" }, + #if defined(WIN32) || defined(__CYGWIN__) /* We permit UNC paths on Windows. By definition UNC * paths must have two components so we should remove the