threads / patch / 27640

patch, 3 partshelp.c: Fix detection of custom merge strategy on cygwin

Subject: [PATCH 1/3] help.c: Fix detection of custom merge strategy on cygwin

## tl;dr

4 messages between Jun 16, 2011 and Jun 18, 2011. Diffs are folded; open one to read it.

replies: 3people: 3as markdown or json

Ramsay Jones· Jun 16, 2011, 20:22 UTC · lore

Test t7606-merge-custom.sh fails on cygwin when git-merge fails with an "Could not find merge strategy 'theirs'" error, despite the test correctly preparing an (executable) git-merge-theirs script.

The cause of the failure is the mis-detection of the executable status of the script, by the is_executable() function, while the load_command_list() function is searching the path for additional merge strategy programs.

Note that the l/stat() "functions" on cygwin are somewhat schizophrenic (see commits adbc0b6, 7faee6b and 7974843), and their behaviour depends on the timing of various git setup and config function calls. In particular, until the "git_dir" has been set (have_git_dir() returns true), the real cygwin (POSIX emulating) l/stat() functions are called. Once "git_dir" has been set, the "native Win32 API" implementations of l/stat() may, or may not, be called depending on the setting of the core.filemode and core.ignorecygwinfstricks config variables.

We also note that, since commit c869753, core.filemode is forced to false, even on NTFS, by git-init and git-clone. A user (or a test) can, of course, reset core.filemode to true explicitly if the filesystem supports it (and he doesn't use any problematic windows software). The test-suite currently runs all tests on cygwin with core.filemode set to false.

Given the above, we see that the built-in merge strategies are correctly detected as executable, since they are checked for before "git_dir" is set, whereas all custom merge strategies are not, since they are checked for after "git_dir" is set.

In order to fix the mis-detection problem, we change the code in is_executable() to re-use the conditional WIN32 code section, which actually looks at the content of the file to determine if the file is executable. On cygwin we also make the additional code conditional on the executable bit of the file mode returned by the initial stat() call. (only the real cygwin function would set the executable bit in the file mode.)

Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
---
 help.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)
Show changes to help.c +4 −1
diff --git a/help.c b/help.c
index 7654f1b..e925ca1 100644
--- a/help.c
+++ b/help.c
@@ -127,7 +127,10 @@ static int is_executable(const char *name)
 	    !S_ISREG(st.st_mode))
 		return 0;
 
-#ifdef WIN32
+#if defined(WIN32) || defined(__CYGWIN__)
+#if defined(__CYGWIN__)
+if ((st.st_mode & S_IXUSR) == 0)
+#endif
 {	/* cannot trust the executable bit, peek into the file instead */
 	char buf[3] = { 0 };
 	int n;
-- 
1.7.5
Junio C Hamano· Jun 16, 2011, 22:24 UTC · re: Ramsay Jones · lore

Re: [PATCH 1/3] help.c: Fix detection of custom merge strategy on cygwin

Ramsay Jones <ramsay@ramsay1.demon.co.uk> writes:
Show 8 quoted lines
> -#ifdef WIN32
> +#if defined(WIN32) || defined(__CYGWIN__)
> +#if defined(__CYGWIN__)
> +if ((st.st_mode & S_IXUSR) == 0)
> +#endif
>  {	/* cannot trust the executable bit, peek into the file instead */
>  	char buf[3] = { 0 };
>  	int n;
This looks somewhat ugly.

I guess we could make the inner #if/#endif slightly more readable by letting the compiler do more work, like this:

	#if defined(WIN32) || defined(__CYGWIN__)
        if (!defined(__CYGWIN__) || !(st.st_mode & S_IXUSR)) {
        	...
	}
        #endif
I dunno.
Ramsay Jones· Jun 18, 2011, 16:57 UTC · re: Junio C Hamano · lore

Re: [PATCH 1/3] help.c: Fix detection of custom merge strategy on cygwin

Junio C Hamano wrote:
Show 12 quoted lines
> Ramsay Jones <ramsay@ramsay1.demon.co.uk> writes:
> 
>> -#ifdef WIN32
>> +#if defined(WIN32) || defined(__CYGWIN__)
>> +#if defined(__CYGWIN__)
>> +if ((st.st_mode & S_IXUSR) == 0)
>> +#endif
>>  {	/* cannot trust the executable bit, peek into the file instead */
>>  	char buf[3] = { 0 };
>>  	int n;
> 
> This looks somewhat ugly.
;-) Yeah, Johannes Sixt had a similar complaint last time ...
Show 5 quoted lines
> I guess we could make the inner #if/#endif slightly more readable by
> letting the compiler do more work, like this:
> 
> 	#if defined(WIN32) || defined(__CYGWIN__)
>         if (!defined(__CYGWIN__) || !(st.st_mode & S_IXUSR)) {
              ^^^^^^^^^
This would have to be something like:
    #if defined(__CYGWIN__)
    #define IS_CYGWIN 1
    #else
    #define IS_CYGWIN 0
    #endif
    if (!IS_CYGWIN || !(st.st_mode & S_IXUSR)) {
no?
Show 5 quoted lines
>         	...
> 	}
>         #endif
> 
> I dunno.
The first version of this patch looked like:
-#ifdef WIN32
+#if defined(WIN32) || defined(__CYGWIN__)
+if ((st.st_mode & S_IXUSR) == 0)
 {	/* cannot trust the executable bit, peek into the file instead */

The idea being that the WIN32 builds (ie MinGW and MSVC) would never set the executable bit, so this should only be false on cygwin when *not* using the WIN32 l/stat implementation. So it should be safe ...

However, I got cold feet (and being lazy didn't want to test on MinGW and MSVC) and decided on the more conservative approach.

Anyway, if you don't mind executing the "WIN32 code block" unnecessarily on cygwin (I don't think it would be too expensive) then we could simply reduce the patch to:

-#ifdef WIN32
+#if defined(WIN32) || defined(__CYGWIN__)
 {	/* cannot trust the executable bit, peek into the file instead */
(I've simply typed the above in my MUA, so not tested, obviously!)
This is exactly what Johannes proposed last year. :)

ATB, Ramsay Jones

Mark Levedahl· Jun 18, 2011, 22:46 UTC · re: Ramsay Jones · lore

Re: [PATCH 1/3] help.c: Fix detection of custom merge strategy on cygwin

On 06/18/2011 12:57 PM, Ramsay Jones wrote:
Show 16 quoted lines
>
> Anyway, if you don't mind executing the "WIN32 code block" unnecessarily
> on cygwin (I don't think it would be too expensive) then we could simply
> reduce the patch to:
>
> -#ifdef WIN32
> +#if defined(WIN32) || defined(__CYGWIN__)
>   {	/* cannot trust the executable bit, peek into the file instead */
>
> (I've simply typed the above in my MUA, so not tested, obviously!)
>
> This is exactly what Johannes proposed last year. :)
>
> ATB,
> Ramsay Jones
>

Please, no. Cygwin's git is already slow enough, and adding yet another peek into a file *after* cygwin already did that is just making it worse.

(Muttering to self: Cygwin's goal is to replicate Linux / Posix behavior under Windows, why did git ever adopt code to make cygwin more like Windows rather than just treating cygwin as another Posix'y environment? Those who want more speed really should just be using the native win32 port and deal with the lack of file modes, crlf issues, etc.)

Mark

← back to recent threads