We fail to guess a sensible directory name for a newly cloned
repository when the path component of the URL is empty. E.g.
cloning a repository 'ssh://user:passw...@example.com/' we create
a directory 'passw...@example.com' for the clone.

Fix this by using parse_connect_url to split host and path
components and explicitly checking whether we need to fall back
to the hostname for guessing a directory name.

Signed-off-by: Patrick Steinhardt <p...@pks.im>
---
 builtin/clone.c | 73 +++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 53 insertions(+), 20 deletions(-)

diff --git a/builtin/clone.c b/builtin/clone.c
index a72ff7e..4547729 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -9,6 +9,7 @@
  */
 
 #include "builtin.h"
+#include "connect.h"
 #include "lockfile.h"
 #include "parse-options.h"
 #include "fetch-pack.h"
@@ -147,34 +148,62 @@ static char *get_repo_path(const char *repo, int 
*is_bundle)
 static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
 {
        const char *end = repo + strlen(repo), *start;
+       char *host, *path;
        size_t len;
        char *dir;
 
+       parse_connect_url(repo, &host, &path);
        /*
-        * Strip trailing spaces, slashes and /.git
+        * If the path component of the URL is empty (e.g. it is
+        * empty or only contains a '/') we fall back to the host
+        * name.
         */
-       while (repo < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
-               end--;
-       if (end - repo > 5 && is_dir_sep(end[-5]) &&
-           !strncmp(end - 4, ".git", 4)) {
-               end -= 5;
-               while (repo < end && is_dir_sep(end[-1]))
+       if (!path || !*path || !strcmp(path, "/")) {
+               if (*host == '\0')
+                       die("No directory name could be guessed.\n"
+                               "Please specify a directory on the command 
line");
+               /*
+                * Strip authentication information if it exists.
+                */
+               start = strchr(host, '@');
+               if (start)
+                       start++;
+               else
+                       start = host;
+               /*
+                * Strip port if it exitsts.
+                */
+               end = strchr(start, ':');
+               if (!end)
+                       end = start + strlen(start);
+               len = end - start;
+       } else {
+               /*
+                * Strip trailing spaces, slashes and /.git
+                */
+               while (repo < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
                        end--;
-       }
+               if (end - repo > 5 && is_dir_sep(end[-5]) &&
+                       !strncmp(end - 4, ".git", 4)) {
+                       end -= 5;
+                       while (repo < end && is_dir_sep(end[-1]))
+                               end--;
+               }
 
-       /*
-        * Find last component, but be prepared that repo could have
-        * the form  "remote.example.com:foo.git", i.e. no slash
-        * in the directory part.
-        */
-       start = end;
-       while (repo < start && !is_dir_sep(start[-1]) && start[-1] != ':')
-               start--;
+               /*
+                * Find last component, but be prepared that repo could have
+                * the form  "remote.example.com:foo.git", i.e. no slash
+                * in the directory part.
+                */
+               start = end;
+               while (repo < start && !is_dir_sep(start[-1]) && start[-1] != 
':')
+                       start--;
 
-       /*
-        * Strip .{bundle,git}.
-        */
-       strip_suffix(start, is_bundle ? ".bundle" : ".git" , &len);
+               /*
+                * Strip .{bundle,git}.
+                */
+               strip_suffix(start, is_bundle ? ".bundle" : ".git" , &len);
+       }
 
        if (is_bare)
                dir = xstrfmt("%.*s.git", (int)len, start);
@@ -203,6 +232,10 @@ static char *guess_dir_name(const char *repo, int 
is_bundle, int is_bare)
                if (out > dir && prev_space)
                        out[-1] = '\0';
        }
+
+       free(host);
+       free(path);
+
        return dir;
 }
 
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to