On Wed, Sep 05, 2012 at 08:23:58PM -0700, Junio C Hamano wrote:
> Nguyen Thai Ngoc Duy <pclo...@gmail.com> writes:
> 
> > diff --git a/path.c b/path.c
> > index 66acd24..ad2881c 100644
> > --- a/path.c
> > +++ b/path.c
> > @@ -503,6 +503,10 @@ int normalize_path_copy(char *dst, const char *src)
> >                 *dst++ = *src++;
> >                 *dst++ = *src++;
> >         }
> > +#ifdef WIN32
> > +       else if (src[0] == '/' && src[1] == '/')
> > +               *dst++ = *src++;
> > +#endif
> 
> The two-byte copy we see above the context is conditional on a nice
> abstraction "has_dos_drive_prefix()" so that we do not have to
> suffer from these ugly ifdefs.  Could we do something similar?

Just an idea. We could unify "[a-z]:" and "//host" into "dos root"
concept. That would teach other code paths about UNC paths too.

Replace has_dos_drive_prefix() with has_dos_root_prefix(). Because the
root component's length is not fixed, offset_1st_component() should be
used instead of hard coding "2".

Something like this. Totally untested.

-- 8< --
diff --git a/cache.h b/cache.h
index 67f28b4..7946489 100644
--- a/cache.h
+++ b/cache.h
@@ -711,7 +711,7 @@ extern char *expand_user_path(const char *path);
 const char *enter_repo(const char *path, int strict);
 static inline int is_absolute_path(const char *path)
 {
-       return is_dir_sep(path[0]) || has_dos_drive_prefix(path);
+       return is_dir_sep(path[0]) || has_dos_root_prefix(path);
 }
 int is_directory(const char *);
 const char *real_path(const char *path);
@@ -721,7 +721,7 @@ int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
+int offset_1st_component(const char *path, int keep_root);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
diff --git a/compat/basename.c b/compat/basename.c
index d8f8a3c..178b60d 100644
--- a/compat/basename.c
+++ b/compat/basename.c
@@ -5,8 +5,7 @@ char *gitbasename (char *path)
 {
        const char *base;
        /* Skip over the disk name in MSDOS pathnames. */
-       if (has_dos_drive_prefix(path))
-               path += 2;
+       path += offset_1st_component(path, 0);
        for (base = path; *path; path++) {
                if (is_dir_sep(*path))
                        base = path + 1;
diff --git a/compat/mingw.h b/compat/mingw.h
index 61a6521..1ca3e19 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -302,7 +302,9 @@ int winansi_fprintf(FILE *stream, const char *format, ...) 
__attribute__((format
  * git specific compatibility
  */
 
-#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':')
+#define has_dos_root_prefix(path) \
+       ((is_dir_sep[(path)[0]] && is_dir_sep[(path)[1]]) \
+        || (isalpha(*(path)) && (path)[1] == ':'))
 #define is_dir_sep(c) ((c) == '/' || (c) == '\\')
 static inline char *mingw_find_last_dir_sep(const char *path)
 {
diff --git a/connect.c b/connect.c
index 55a85ad..3d9f7fe 100644
--- a/connect.c
+++ b/connect.c
@@ -521,7 +521,7 @@ struct child_process *git_connect(int fd[2], const char 
*url_orig,
                end = host;
 
        path = strchr(end, c);
-       if (path && !has_dos_drive_prefix(end)) {
+       if (path && (!isalpha(*end) || end[1] != ':')) {
                if (c == ':') {
                        protocol = PROTO_SSH;
                        *path++ = '\0';
diff --git a/git-compat-util.h b/git-compat-util.h
index 35b095e..c6656e2 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -216,8 +216,8 @@ extern char *gitbasename(char *);
 #define STRIP_EXTENSION ""
 #endif
 
-#ifndef has_dos_drive_prefix
-#define has_dos_drive_prefix(path) 0
+#ifndef has_dos_root_prefix
+#define has_dos_root_prefix(path) 0
 #endif
 
 #ifndef is_dir_sep
diff --git a/path.c b/path.c
index 66acd24..0e4e2d7 100644
--- a/path.c
+++ b/path.c
@@ -498,11 +498,12 @@ const char *relative_path(const char *abs, const char 
*base)
 int normalize_path_copy(char *dst, const char *src)
 {
        char *dst0;
+       int i, len;
 
-       if (has_dos_drive_prefix(src)) {
+       len = offset_1st_component(src, 1);
+       for (i = 0; i < len; i++)
                *dst++ = *src++;
-               *dst++ = *src++;
-       }
+
        dst0 = dst;
 
        if (is_dir_sep(*src)) {
@@ -702,9 +703,18 @@ int daemon_avoid_alias(const char *p)
        }
 }
 
-int offset_1st_component(const char *path)
+int offset_1st_component(const char *path, int keep_root)
 {
-       if (has_dos_drive_prefix(path))
-               return 2 + is_dir_sep(path[2]);
-       return is_dir_sep(path[0]);
+       if (has_dos_root_prefix(path)) {
+               if (path[1] == ':')
+                       return 2 + (keep_root ? 0 : is_dir_sep(path[2]));
+               else {
+                       const char *s = strchr(path + 2, '/');
+                       /* //host is considered a "drive" */
+                       if (s)
+                               return s - path + (keep_root ? 0 : 1);
+               }
+       }
+
+       return keep_root ? 0 : is_dir_sep(path[0]);
 }
diff --git a/read-cache.c b/read-cache.c
index 2f8159f..d4d339a 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -755,7 +755,7 @@ int verify_path(const char *path)
 {
        char c;
 
-       if (has_dos_drive_prefix(path))
+       if (has_dos_root_prefix(path))
                return 0;
 
        goto inside;
diff --git a/setup.c b/setup.c
index 9139bee..e010cf8 100644
--- a/setup.c
+++ b/setup.c
@@ -26,7 +26,7 @@ static char *prefix_path_gently(const char *prefix, int len, 
const char *path)
                if (!work_tree)
                        goto error_out;
                len = strlen(work_tree);
-               root_len = offset_1st_component(work_tree);
+               root_len = offset_1st_component(work_tree, 0);
                total = strlen(sanitized) + 1;
                if (strncmp(sanitized, work_tree, len) ||
                    (len > root_len && sanitized[len] != '\0' && sanitized[len] 
!= '/')) {
@@ -587,7 +587,7 @@ static const char *setup_bare_git_dir(char *cwd, int 
offset, int len, int *nongi
        if (offset != len) {
                if (chdir(cwd))
                        die_errno("Cannot come back to cwd");
-               root_len = offset_1st_component(cwd);
+               root_len = offset_1st_component(cwd, 0);
                cwd[offset > root_len ? offset : root_len] = '\0';
                set_git_dir(cwd);
        }
@@ -654,7 +654,7 @@ static const char *setup_git_directory_gently_1(int 
*nongit_ok)
                return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok);
 
        ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs);
-       if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
+       if (ceil_offset < 0 && has_dos_root_prefix(cwd))
                ceil_offset = 1;
 
        /*
diff --git a/sha1_file.c b/sha1_file.c
index af5cfbd..21ce020 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -102,7 +102,7 @@ int mkdir_in_gitdir(const char *path)
 
 int safe_create_leading_directories(char *path)
 {
-       char *pos = path + offset_1st_component(path);
+       char *pos = path + offset_1st_component(path, 0);
        struct stat st;
 
        while (pos) {
diff --git a/transport.c b/transport.c
index 1811b50..5141e8f 100644
--- a/transport.c
+++ b/transport.c
@@ -869,7 +869,7 @@ static int is_local(const char *url)
        const char *colon = strchr(url, ':');
        const char *slash = strchr(url, '/');
        return !colon || (slash && slash < colon) ||
-               has_dos_drive_prefix(url);
+               has_dos_root_prefix(url);
 }
 
 static int is_file(const char *url)
-- 8< --
--
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