You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2010/06/25 13:31:42 UTC
svn commit: r957893 - in /subversion/trunk/subversion:
include/svn_dirent_uri.h libsvn_ra_local/split_url.c
libsvn_subr/dirent_uri.c tests/libsvn_subr/dirent_uri-test.c
Author: rhuijben
Date: Fri Jun 25 11:31:41 2010
New Revision: 957893
URL: http://svn.apache.org/viewvc?rev=957893&view=rev
Log:
Move the knowledge on how file:/// urls are handled out of libsvn_ra_local,
into libsvn_subr's dirent_uri.c to allow managing and testing all the
uri<->dirent translations in one place.
* subversion/include/svn_dirent_uri.h
(svn_uri_get_dirent_from_file_url): New function.
* subversion/libsvn_ra_local/split_url.c
(includes): Add svn_dirent_uri.h.
(svn_ra_local__split_URL): Use new svn_uri_get_dirent_from_file_url
function and calculate the url and fs path from the result of this
function.
* subversion/libsvn_subr/dirent_uri.c
(svn_uri_get_dirent_from_file_url): New function, based on
svn_ra_local__split_URL. Fix some errors on handling drives and unc
paths on Windows, found by adding some tests. Also remove an
obsolete comment on how UNC could be used a long time ago, since that
support is broken since at least 1.5.
* subversion/tests/libsvn_subr/dirent_uri-test.c
(test_dirent_from_file_url): New function.
(test_funcs): Add test_dirent_from_file_url.
Modified:
subversion/trunk/subversion/include/svn_dirent_uri.h
subversion/trunk/subversion/libsvn_ra_local/split_url.c
subversion/trunk/subversion/libsvn_subr/dirent_uri.c
subversion/trunk/subversion/tests/libsvn_subr/dirent_uri-test.c
Modified: subversion/trunk/subversion/include/svn_dirent_uri.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_dirent_uri.h?rev=957893&r1=957892&r2=957893&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_dirent_uri.h (original)
+++ subversion/trunk/subversion/include/svn_dirent_uri.h Fri Jun 25 11:31:41 2010
@@ -779,6 +779,16 @@ svn_dirent_is_under_root(char **full_pat
const char *path,
apr_pool_t *pool);
+/* Converts a file:// url into a proper dirent by using the platform specific
+ * files:// rules.
+ *
+ * @since New in 1.7.
+ */
+svn_error_t *
+svn_uri_get_dirent_from_file_url(const char **dirent,
+ const char *url,
+ apr_pool_t *pool);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
Modified: subversion/trunk/subversion/libsvn_ra_local/split_url.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_local/split_url.c?rev=957893&r1=957892&r2=957893&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_local/split_url.c (original)
+++ subversion/trunk/subversion/libsvn_ra_local/split_url.c Fri Jun 25 11:31:41 2010
@@ -24,6 +24,7 @@
#include "ra_local.h"
#include <string.h>
#include "svn_path.h"
+#include "svn_dirent_uri.h"
#include "svn_private_config.h"
@@ -35,129 +36,30 @@ svn_ra_local__split_URL(svn_repos_t **re
apr_pool_t *pool)
{
svn_error_t *err = SVN_NO_ERROR;
- const char *repos_root;
- const char *hostname, *path;
+ const char *repos_dirent;
+ const char *repos_root_dirent;
svn_stringbuf_t *urlbuf;
/* Verify that the URL is well-formed (loosely) */
-
- /* First, check for the "file://" prefix. */
+ /* First, check for the "file://" prefix, to avoid assertion in tests */
if (strncmp(URL, "file://", 7) != 0)
- return svn_error_createf
- (SVN_ERR_RA_ILLEGAL_URL, NULL,
- _("Local URL '%s' does not contain 'file://' prefix"), URL);
-
- /* Then, skip what's between the "file://" prefix and the next
- occurance of '/' -- this is the hostname, and we are considering
- everything from that '/' until the end of the URL to be the
- absolute path portion of the URL.
- If we got just "file://", treat it the same as "file:///". */
- hostname = URL + 7;
- if (*hostname == '\0')
- {
- path = "/";
- hostname = NULL;
- }
- else
- {
- path = strchr(hostname, '/');
- if (! path)
- return svn_error_createf
- (SVN_ERR_RA_ILLEGAL_URL, NULL,
- _("Local URL '%s' contains only a hostname, no path"), URL);
-
- /* Treat localhost as an empty hostname. */
- if (hostname != path)
- {
- hostname = svn_path_uri_decode(apr_pstrmemdup(pool, hostname,
- path - hostname), pool);
- if (strncmp(hostname, "localhost", 9) == 0)
- hostname = NULL;
- }
- else
- hostname = NULL;
- }
-
- /* Duplicate the URL, starting at the top of the path.
- At the same time, we URI-decode the path. */
-#if defined(WIN32) || defined(__CYGWIN__)
- /* On Windows, we'll typically have to skip the leading / if the
- path starts with a drive letter. Like most Web browsers, We
- support two variants of this scheme:
-
- file:///X:/path and
- file:///X|/path
-
- Note that, at least on WinNT and above, file:////./X:/path will
- also work, so we must make sure the transformation doesn't break
- that, and file:///path (that looks within the current drive
- only) should also keep working.
- If we got a non-empty hostname other than localhost, we convert this
- into an UNC path. In this case, we obviously don't strip the slash
- even if the path looks like it starts with a drive letter.
- Another thing to remember is that the form file:///\machine/share
- was the only way to access UNC paths in svn before 1.2. We
- need to support that for compatibility with old working copies.
- */
- {
- static const char valid_drive_letters[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
- /* Casting away const! */
- char *dup_path = (char *)svn_path_uri_decode(path, pool);
- if (!hostname && dup_path[1] && strchr(valid_drive_letters, dup_path[1])
- && (dup_path[2] == ':' || dup_path[2] == '|')
- && (dup_path[3] == '/' || dup_path[3] == '\0'))
- {
- /* Skip the leading slash. */
- ++dup_path;
- /* We're using path below to calculate fs_path, so keep it in sync. */
- ++path;
- if (dup_path[1] == '|')
- dup_path[1] = ':';
-
- if (dup_path[3] == '\0')
- {
- /* A valid dirent for the driveroot must be like "C:/" instead of
- just "C:" or svn_dirent_join() will use the current directory
- on the drive instead */
-
- char *new_path = apr_pcalloc(pool, 4);
- new_path[0] = dup_path[0];
- new_path[1] = ':';
- new_path[2] = '/';
- new_path[3] = '\0';
- }
- }
- if (hostname)
- /* We still know that the path starts with a slash. */
- repos_root = apr_pstrcat(pool, "//", hostname, path, NULL);
- else
- repos_root = dup_path;
- }
-#else
- /* Currently, the only hostnames we are allowing on non-Win32 platforms
- are the empty string and 'localhost'. */
- if (hostname)
- return svn_error_createf
- (SVN_ERR_RA_ILLEGAL_URL, NULL,
- _("Local URL '%s' contains unsupported hostname"), URL);
+ return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
+ _("Local URL '%s' does not contain 'file://' "
+ "prefix"), URL);
- repos_root = svn_path_uri_decode(path, pool);
-#endif
+ SVN_ERR(svn_uri_get_dirent_from_file_url(&repos_dirent, URL, pool));
/* Search for a repository in the full path. */
- repos_root = svn_repos_find_root_path(repos_root, pool);
- if (!repos_root)
- return svn_error_createf
- (SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED, NULL,
- _("Unable to open repository '%s'"), URL);
+ repos_root_dirent = svn_repos_find_root_path(repos_dirent, pool);
+ if (!repos_root_dirent)
+ return svn_error_createf(SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED, NULL,
+ _("Unable to open repository '%s'"), URL);
/* Attempt to open a repository at URL. */
- err = svn_repos_open(repos, repos_root, pool);
+ err = svn_repos_open(repos, repos_root_dirent, pool);
if (err)
- return svn_error_createf
- (SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED, err,
- _("Unable to open repository '%s'"), URL);
+ return svn_error_createf(SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED, err,
+ _("Unable to open repository '%s'"), URL);
/* Assert capabilities directly, since client == server. */
{
@@ -166,26 +68,17 @@ svn_ra_local__split_URL(svn_repos_t **re
SVN_ERR(svn_repos_remember_client_capabilities(*repos, caps));
}
- /* What remains of URL after being hacked at in the previous step is
- REPOS_URL. FS_PATH is what we've hacked off in the process.
- Note that path is not encoded and what we gave to svn_root_find_root_path
- may have been destroyed by that function. So we have to decode it once
- more. But then, it is ours...
- We want the suffix of path after the repos root part. Note that
- repos_root may contain //hostname, but path doesn't. */
- *fs_path = svn_path_uri_decode(path, pool)
- + (strlen(repos_root)
- - (hostname ? strlen(hostname) + 2 : 0));
-
- /* Ensure that *FS_PATH has its leading slash. */
- if (**fs_path != '/')
- *fs_path = apr_pstrcat(pool, "/", *fs_path, NULL);
+ *fs_path = &repos_dirent[strlen(repos_root_dirent)];
+
+ if (**fs_path == '\0')
+ *fs_path = "/";
/* Remove the path components in *fs_path from the original URL, to get
the URL to the repository root. */
urlbuf = svn_stringbuf_create(URL, pool);
svn_path_remove_components(urlbuf,
- svn_path_component_count(*fs_path));
+ svn_path_component_count(repos_dirent)
+ - svn_path_component_count(repos_root_dirent));
*repos_url = urlbuf->data;
return SVN_NO_ERROR;
Modified: subversion/trunk/subversion/libsvn_subr/dirent_uri.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/dirent_uri.c?rev=957893&r1=957892&r2=957893&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/dirent_uri.c (original)
+++ subversion/trunk/subversion/libsvn_subr/dirent_uri.c Fri Jun 25 11:31:41 2010
@@ -2265,3 +2265,122 @@ svn_dirent_is_under_root(char **full_pat
return status == APR_SUCCESS ? TRUE : FALSE;
}
+
+svn_error_t *
+svn_uri_get_dirent_from_file_url(const char **dirent,
+ const char *url,
+ apr_pool_t *pool)
+{
+ const char *hostname, *path;
+
+ assert(svn_uri_is_canonical(url, pool));
+ assert(svn_path_is_url(url));
+
+ /* Verify that the URL is well-formed (loosely) */
+
+ /* First, check for the "file://" prefix. */
+ if (strncmp(url, "file://", 7) != 0)
+ return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
+ _("Local URL '%s' does not contain 'file://' "
+ "prefix"), url);
+
+ /* Then, skip what's between the "file://" prefix and the next
+ occurance of '/' -- this is the hostname, and we are considering
+ everything from that '/' until the end of the URL to be the
+ absolute path portion of the URL.
+ If we got just "file://", treat it the same as "file:///". */
+ hostname = url + 7;
+ if (*hostname == '\0')
+ {
+ path = "/";
+ hostname = NULL;
+ }
+ else
+ {
+ path = strchr(hostname, '/');
+ if (! path)
+ return
+ svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
+ _("Local URL '%s' contains only a hostname, "
+ "no path"), url);
+
+ /* Treat localhost as an empty hostname. */
+ if (hostname != path)
+ {
+ hostname = svn_path_uri_decode(apr_pstrmemdup(pool, hostname,
+ path - hostname), pool);
+ if (strncmp(hostname, "localhost", 9) == 0)
+ hostname = NULL;
+ }
+ else
+ hostname = NULL;
+ }
+
+ /* Duplicate the URL, starting at the top of the path.
+ At the same time, we URI-decode the path. */
+#if defined(WIN32) || defined(__CYGWIN__)
+ /* On Windows, we'll typically have to skip the leading / if the
+ path starts with a drive letter. Like most Web browsers, We
+ support two variants of this scheme:
+
+ file:///X:/path and
+ file:///X|/path
+
+ Note that, at least on WinNT and above, file:////./X:/path will
+ also work, so we must make sure the transformation doesn't break
+ that, and file:///path (that looks within the current drive
+ only) should also keep working.
+ If we got a non-empty hostname other than localhost, we convert this
+ into an UNC path. In this case, we obviously don't strip the slash
+ even if the path looks like it starts with a drive letter.
+ */
+ {
+ static const char valid_drive_letters[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ /* Casting away const! */
+ char *dup_path = (char *)svn_path_uri_decode(path, pool);
+
+ /* This check assumes ':' and '|' are already decoded! */
+ if (!hostname && dup_path[1] && strchr(valid_drive_letters, dup_path[1])
+ && (dup_path[2] == ':' || dup_path[2] == '|'))
+ {
+ /* Skip the leading slash. */
+ ++dup_path;
+
+ if (dup_path[1] == '|')
+ dup_path[1] = ':';
+
+ if (dup_path[2] == '/' || dup_path[2] == '\0')
+ {
+ if (dup_path[2] == '\0')
+ {
+ /* A valid dirent for the driveroot must be like "C:/" instead of
+ just "C:" or svn_dirent_join() will use the current directory
+ on the drive instead */
+ char *new_path = apr_pcalloc(pool, 4);
+ new_path[0] = dup_path[0];
+ new_path[1] = ':';
+ new_path[2] = '/';
+ new_path[3] = '\0';
+ dup_path = new_path;
+ }
+ }
+ }
+ if (hostname)
+ /* We still know that the path starts with a slash. */
+ *dirent = apr_pstrcat(pool, "//", hostname, dup_path, NULL);
+ else
+ *dirent = dup_path;
+ }
+#else
+ /* Currently, the only hostnames we are allowing on non-Win32 platforms
+ are the empty string and 'localhost'. */
+ if (hostname)
+ return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
+ _("Local URL '%s' contains unsupported hostname"),
+ URL);
+
+ repos_root = svn_path_uri_decode(path, pool);
+#endif
+ return SVN_NO_ERROR;
+}
Modified: subversion/trunk/subversion/tests/libsvn_subr/dirent_uri-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_subr/dirent_uri-test.c?rev=957893&r1=957892&r2=957893&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/dirent_uri-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_subr/dirent_uri-test.c Fri Jun 25 11:31:41 2010
@@ -2670,6 +2670,45 @@ test_relpath_internal_style(apr_pool_t *
return SVN_NO_ERROR;
}
+static svn_error_t *
+test_dirent_from_file_url(apr_pool_t *pool)
+{
+ struct {
+ const char *url;
+ const char *result;
+ } tests[] = {
+ { "file:///dir", "/dir" },
+ { "file:///dir/path", "/dir/path" },
+ { "file://localhost/dir", "/dir" },
+ { "file://localhost/dir/path", "/dir/path" },
+#if defined(WIN32)
+ { "file://server/share", "//server/share" },
+ { "file://server/share/dir", "//server/share/dir" },
+ { "file:///A:", "A:/" },
+ { "file:///A:/dir", "A:/dir" },
+ { "file:///A:dir", "A:dir" },
+ { "file:///A%7C", "A:/" },
+ { "file:///A%7C/dir", "A:/dir" },
+ { "file:///A%7Cdir", "A:dir" },
+#endif
+ };
+ int i;
+
+ for (i = 0; i < COUNT_OF(tests); i++)
+ {
+ const char *result;
+
+ SVN_ERR(svn_uri_get_dirent_from_file_url(&result, tests[i].url, pool));
+
+ if (strcmp(result, tests[i].result))
+ return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+ "svn_relpath_internal_style(\"%s\") returned "
+ "\"%s\" expected \"%s\"",
+ tests[i].url, result, tests[i].result);
+ }
+
+ return SVN_NO_ERROR;
+}
/* The test table. */
@@ -2762,5 +2801,7 @@ struct svn_test_descriptor_t test_funcs[
"test svn_dirent_internal_style"),
SVN_TEST_PASS2(test_relpath_internal_style,
"test svn_relpath_internal_style"),
+ SVN_TEST_PASS2(test_dirent_from_file_url,
+ "test svn_uri_get_dirent_from_file_url"),
SVN_TEST_NULL
};