2 * checkout.c : read a repository and drive a checkout editor.
4 * ====================================================================
5 * Copyright (c) 2000-2004 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
23 #include "svn_private_config.h"
27 svn_ra_local__split_URL(svn_repos_t
**repos
,
28 const char **repos_url
,
33 svn_error_t
*err
= SVN_NO_ERROR
;
34 const char *repos_root
;
35 const char *hostname
, *path
;
36 svn_stringbuf_t
*urlbuf
;
38 /* Verify that the URL is well-formed (loosely) */
40 /* First, check for the "file://" prefix. */
41 if (strncmp(URL
, "file://", 7) != 0)
42 return svn_error_createf
43 (SVN_ERR_RA_ILLEGAL_URL
, NULL
,
44 _("Local URL '%s' does not contain 'file://' prefix"), URL
);
46 /* Then, skip what's between the "file://" prefix and the next
47 occurance of '/' -- this is the hostname, and we are considering
48 everything from that '/' until the end of the URL to be the
49 absolute path portion of the URL. */
51 path
= strchr(hostname
, '/');
53 return svn_error_createf
54 (SVN_ERR_RA_ILLEGAL_URL
, NULL
,
55 _("Local URL '%s' contains only a hostname, no path"), URL
);
57 /* Treat localhost as an empty hostname. */
60 hostname
= svn_path_uri_decode(apr_pstrmemdup(pool
, hostname
,
61 path
- hostname
), pool
);
62 if (strncmp(hostname
, "localhost", 9) == 0)
68 /* Duplicate the URL, starting at the top of the path.
69 At the same time, we URI-decode the path. */
70 #if defined(WIN32) || defined(__CYGWIN__)
71 /* On Windows, we'll typically have to skip the leading / if the
72 path starts with a drive letter. Like most Web browsers, We
73 support two variants of this scheme:
78 Note that, at least on WinNT and above, file:////./X:/path will
79 also work, so we must make sure the transformation doesn't break
80 that, and file:///path (that looks within the current drive
81 only) should also keep working.
82 If we got a non-empty hostname other than localhost, we convert this
83 into an UNC path. In this case, we obviously don't strip the slash
84 even if the path looks like it starts with a drive letter.
85 Another thing to remember is that the form file:///\machine/share
86 was the only way to access UNC paths in svn before 1.2. We
87 need to support that for compatibility with old working copies.
90 static const char valid_drive_letters
[] =
91 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
92 /* Casting away const! */
93 char *dup_path
= (char *)svn_path_uri_decode(path
, pool
);
94 if (!hostname
&& dup_path
[1] && strchr(valid_drive_letters
, dup_path
[1])
95 && (dup_path
[2] == ':' || dup_path
[2] == '|')
96 && dup_path
[3] == '/')
98 /* Skip the leading slash. */
100 /* We're using path below to calculate fs_path, so keep it in sync. */
102 if (dup_path
[1] == '|')
106 /* We still know that the path starts with a slash. */
107 repos_root
= apr_pstrcat(pool
, "//", hostname
, path
, NULL
);
109 repos_root
= dup_path
;
112 /* Currently, the only hostnames we are allowing on non-Win32 platforms
113 are the empty string and 'localhost'. */
115 return svn_error_createf
116 (SVN_ERR_RA_ILLEGAL_URL
, NULL
,
117 _("Local URL '%s' contains unsupported hostname"), URL
);
119 repos_root
= svn_path_uri_decode(path
, pool
);
122 /* Search for a repository in the full path. */
123 repos_root
= svn_repos_find_root_path(repos_root
, pool
);
125 return svn_error_createf
126 (SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED
, NULL
,
127 _("Unable to open repository '%s'"), URL
);
129 /* Attempt to open a repository at URL. */
130 err
= svn_repos_open(repos
, repos_root
, pool
);
132 return svn_error_createf
133 (SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED
, err
,
134 _("Unable to open repository '%s'"), URL
);
136 /* Assert capabilities directly, since client == server. */
138 apr_array_header_t
*caps
= apr_array_make(pool
, 1, sizeof(const char *));
139 APR_ARRAY_PUSH(caps
, const char *) = SVN_RA_CAPABILITY_MERGEINFO
;
140 SVN_ERR(svn_repos_remember_client_capabilities(*repos
, caps
));
143 /* What remains of URL after being hacked at in the previous step is
144 REPOS_URL. FS_PATH is what we've hacked off in the process.
145 Note that path is not encoded and what we gave to svn_root_find_root_path
146 may have been destroyed by that function. So we have to decode it once
147 more. But then, it is ours...
148 We want the suffix of path after the repos root part. Note that
149 repos_root may contain //hostname, but path doesn't. */
150 *fs_path
= svn_path_uri_decode(path
, pool
)
151 + (strlen(repos_root
)
152 - (hostname
? strlen(hostname
) + 2 : 0));
154 /* Ensure that *FS_PATH has its leading slash. */
155 if (**fs_path
!= '/')
156 *fs_path
= apr_pstrcat(pool
, "/", *fs_path
, NULL
);
158 /* Remove the path components in *fs_path from the original URL, to get
159 the URL to the repository root. */
160 urlbuf
= svn_stringbuf_create(URL
, pool
);
161 svn_path_remove_components(urlbuf
,
162 svn_path_component_count(*fs_path
));
163 *repos_url
= urlbuf
->data
;