Skip to content

Commit

Permalink
git clone <url> C:\cygwin\home\USER\repo' is working (again)
Browse files Browse the repository at this point in the history
A regression for cygwin users was introduced with commit 05b458c,
 "real_path: resolve symlinks by hand".

In the the commit message we read:
  The current implementation of real_path uses chdir() in order to resolve
    symlinks.  Unfortunately this isn't thread-safe as chdir() affects a
      process as a whole...

The old (and non-thread-save) OS calls chdir()/pwd() had been
replaced by a string operation.
The cygwin layer "knows" that "C:\cygwin" is an absolute path,
but the new string operation does not.

"git clone <url> C:\cygwin\home\USER\repo" fails like this:
fatal: Invalid path '/home/USER/repo/C:\cygwin\home\USER\repo'

The solution is to implement has_dos_drive_prefix(), skip_dos_drive_prefix()
is_dir_sep(), offset_1st_component() and convert_slashes() for cygwin
in the same way as it is done in 'Git for Windows' in compat/mingw.[ch]

Extract the needed code into compat/win32/path-utils.[ch] and use it
for cygwin as well.

Reported-by: Steven Penny <svnpenn@gmail.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
tboegi authored and gitster committed Dec 26, 2018
1 parent 98cdfbb commit 1cadad6
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 72 deletions.
19 changes: 0 additions & 19 deletions compat/cygwin.c

This file was deleted.

2 changes: 0 additions & 2 deletions compat/cygwin.h

This file was deleted.

29 changes: 1 addition & 28 deletions compat/mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ static inline int needs_hiding(const char *path)
return 0;

/* We cannot use basename(), as it would remove trailing slashes */
mingw_skip_dos_drive_prefix((char **)&path);
win32_skip_dos_drive_prefix((char **)&path);
if (!*path)
return 0;

Expand Down Expand Up @@ -2043,33 +2043,6 @@ pid_t waitpid(pid_t pid, int *status, int options)
return -1;
}

int mingw_skip_dos_drive_prefix(char **path)
{
int ret = has_dos_drive_prefix(*path);
*path += ret;
return ret;
}

int mingw_offset_1st_component(const char *path)
{
char *pos = (char *)path;

/* unc paths */
if (!skip_dos_drive_prefix(&pos) &&
is_dir_sep(pos[0]) && is_dir_sep(pos[1])) {
/* skip server name */
pos = strpbrk(pos + 2, "\\/");
if (!pos)
return 0; /* Error: malformed unc path */

do {
pos++;
} while (*pos && !is_dir_sep(*pos));
}

return pos + is_dir_sep(*pos) - path;
}

int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
{
int upos = 0, wpos = 0;
Expand Down
20 changes: 0 additions & 20 deletions compat/mingw.h
Original file line number Diff line number Diff line change
Expand Up @@ -397,32 +397,12 @@ HANDLE winansi_get_osfhandle(int fd);
* git specific compatibility
*/

#define has_dos_drive_prefix(path) \
(isalpha(*(path)) && (path)[1] == ':' ? 2 : 0)
int mingw_skip_dos_drive_prefix(char **path);
#define skip_dos_drive_prefix mingw_skip_dos_drive_prefix
static inline int mingw_is_dir_sep(int c)
{
return c == '/' || c == '\\';
}
#define is_dir_sep mingw_is_dir_sep
static inline char *mingw_find_last_dir_sep(const char *path)
{
char *ret = NULL;
for (; *path; ++path)
if (is_dir_sep(*path))
ret = (char *)path;
return ret;
}
static inline void convert_slashes(char *path)
{
for (; *path; path++)
if (*path == '\\')
*path = '/';
}
#define find_last_dir_sep mingw_find_last_dir_sep
int mingw_offset_1st_component(const char *path);
#define offset_1st_component mingw_offset_1st_component
#define PATH_SEP ';'
#if !defined(__MINGW64_VERSION_MAJOR) && (!defined(_MSC_VER) || _MSC_VER < 1800)
#define PRIuMAX "I64u"
Expand Down
28 changes: 28 additions & 0 deletions compat/win32/path-utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "../../git-compat-util.h"

int win32_skip_dos_drive_prefix(char **path)
{
int ret = has_dos_drive_prefix(*path);
*path += ret;
return ret;
}

int win32_offset_1st_component(const char *path)
{
char *pos = (char *)path;

/* unc paths */
if (!skip_dos_drive_prefix(&pos) &&
is_dir_sep(pos[0]) && is_dir_sep(pos[1])) {
/* skip server name */
pos = strpbrk(pos + 2, "\\/");
if (!pos)
return 0; /* Error: malformed unc path */

do {
pos++;
} while (*pos && !is_dir_sep(*pos));
}

return pos + is_dir_sep(*pos) - path;
}
20 changes: 20 additions & 0 deletions compat/win32/path-utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#define has_dos_drive_prefix(path) \
(isalpha(*(path)) && (path)[1] == ':' ? 2 : 0)
int win32_skip_dos_drive_prefix(char **path);
#define skip_dos_drive_prefix win32_skip_dos_drive_prefix
static inline int win32_is_dir_sep(int c)
{
return c == '/' || c == '\\';
}
#define is_dir_sep win32_is_dir_sep
static inline char *win32_find_last_dir_sep(const char *path)
{
char *ret = NULL;
for (; *path; ++path)
if (is_dir_sep(*path))
ret = (char *)path;
return ret;
}
#define find_last_dir_sep win32_find_last_dir_sep
int win32_offset_1st_component(const char *path);
#define offset_1st_component win32_offset_1st_component
3 changes: 2 additions & 1 deletion config.mak.uname
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ ifeq ($(uname_O),Cygwin)
UNRELIABLE_FSTAT = UnfortunatelyYes
OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
MMAP_PREVENTS_DELETE = UnfortunatelyYes
COMPAT_OBJS += compat/cygwin.o
COMPAT_OBJS += compat/win32/path-utils.o
FREAD_READS_DIRECTORIES = UnfortunatelyYes
endif
ifeq ($(uname_S),FreeBSD)
Expand Down Expand Up @@ -536,6 +536,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
COMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
COMPAT_OBJS += compat/mingw.o compat/winansi.o \
compat/win32/path-utils.o \
compat/win32/pthread.o compat/win32/syslog.o \
compat/win32/dirent.o
BASIC_CFLAGS += -DWIN32 -DPROTECT_NTFS_DEFAULT=1
Expand Down
3 changes: 2 additions & 1 deletion git-compat-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,11 @@
#endif

#if defined(__CYGWIN__)
#include "compat/cygwin.h"
#include "compat/win32/path-utils.h"
#endif
#if defined(__MINGW32__)
/* pull in Windows compatibility stuff */
#include "compat/win32/path-utils.h"
#include "compat/mingw.h"
#elif defined(_MSC_VER)
#include "compat/msvc.h"
Expand Down
2 changes: 1 addition & 1 deletion t/t5601-clone.sh
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ test_clone_url () {
expect_ssh "$@"
}

test_expect_success !MINGW 'clone c:temp is ssl' '
test_expect_success !MINGW,!CYGWIN 'clone c:temp is ssl' '
test_clone_url c:temp c temp
'

Expand Down

0 comments on commit 1cadad6

Please sign in to comment.