{"thread":{"id":"41019","subject":"[PATCH] mingw: emulate write(2) that fails with a EPIPE","startedAt":"2015-12-16T12:14:57Z","lastAt":"2015-12-21T16:59:56Z","messageCount":13,"participants":["Johannes Schindelin","Junio C Hamano","Eric Sunshine","Johannes Sixt"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"274564","messageId":"01da36219c18373f8507e19035e141d7e56b2d18.1450267413.git.johannes.schindelin@gmx.de","threadId":"41019","inReplyTo":null,"subject":"[PATCH] mingw: emulate write(2) that fails with a EPIPE","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2015-12-16T12:14:57Z","receivedAt":"2015-12-16T12:14:57Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"On Windows, when writing to a pipe fails, errno is always\nEINVAL. However, Git expects it to be EPIPE.\n\nAccording to the documentation, there are two cases in which write()\ntriggers EINVAL: the buffer is NULL, or the length is odd but the mode\nis 16-bit Unicode (the broken pipe is not mentioned as possible cause).\nGit never sets the file mode to anything but binary, therefore we know\nthat errno should actually be EPIPE if it is EINVAL and the buffer is\nnot NULL.\n\nSee https://msdn.microsoft.com/en-us/library/1570wh78.aspx for more\ndetails.\n\nThis works around t5571.11 failing with v2.6.4 on Windows.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n compat/mingw.h | 18 ++++++++++++++++++\n 1 file changed, 18 insertions(+)\n\ndiff --git a/compat/mingw.h b/compat/mingw.h\nindex 738865c..2aca347 100644\n--- a/compat/mingw.h\n+++ b/compat/mingw.h\n@@ -210,6 +210,24 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);\n int mingw_fflush(FILE *stream);\n #define fflush mingw_fflush\n \n+static inline ssize_t mingw_write(int fd, const void *buf, size_t len)\n+{\n+\tssize_t result = write(fd, buf, len);\n+\n+\tif (result < 0 && errno == EINVAL && buf) {\n+\t\t/* check if fd is a pipe */\n+\t\tHANDLE h = (HANDLE) _get_osfhandle(fd);\n+\t\tif (GetFileType(h) == FILE_TYPE_PIPE)\n+\t\t\terrno = EPIPE;\n+\t\telse\n+\t\t\terrno = EINVAL;\n+\t}\n+\n+\treturn result;\n+}\n+\n+#define write mingw_write\n+\n int mingw_access(const char *filename, int mode);\n #undef access\n #define access mingw_access\n-- \n2.6.3.windows.1.300.g1c25e49\n"},{"id":"274596","messageId":"xmqq7fkedyx7.fsf@gitster.mtv.corp.google.com","threadId":"41019","inReplyTo":"01da36219c18373f8507e19035e141d7e56b2d18.1450267413.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH] mingw: emulate write(2) that fails with a EPIPE","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T18:35:32Z","receivedAt":"2015-12-16T18:35:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> On Windows, when writing to a pipe fails, errno is always\n> EINVAL. However, Git expects it to be EPIPE.\n>\n> According to the documentation, there are two cases in which write()\n> triggers EINVAL: the buffer is NULL, or the length is odd but the mode\n> is 16-bit Unicode (the broken pipe is not mentioned as possible cause).\n> Git never sets the file mode to anything but binary, therefore we know\n> that errno should actually be EPIPE if it is EINVAL and the buffer is\n> not NULL.\n\nMakes sense.\n\n>  int mingw_fflush(FILE *stream);\n>  #define fflush mingw_fflush\n>  \n> +static inline ssize_t mingw_write(int fd, const void *buf, size_t len)\n> +{\n> +\tssize_t result = write(fd, buf, len);\n> +\n> +\tif (result < 0 && errno == EINVAL && buf) {\n> +\t\t/* check if fd is a pipe */\n> +\t\tHANDLE h = (HANDLE) _get_osfhandle(fd);\n> +\t\tif (GetFileType(h) == FILE_TYPE_PIPE)\n> +\t\t\terrno = EPIPE;\n> +\t\telse\n> +\t\t\terrno = EINVAL;\n> +\t}\n> +\n> +\treturn result;\n> +}\n> +\n> +#define write mingw_write\n> +\n\nIt strikes me a bit strange to see this inlined compared to what\nappears in the context.  Shouldn't the implementation be done in\ncompat/mingw.c like all others?\n\n>  int mingw_access(const char *filename, int mode);\n>  #undef access\n>  #define access mingw_access\n"},{"id":"274597","messageId":"CAPig+cQzCHtyVs47=ASs5V2BSV7gpVszbdTFydiRhnz3gtD2Qw@mail.gmail.com","threadId":"41019","inReplyTo":"01da36219c18373f8507e19035e141d7e56b2d18.1450267413.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH] mingw: emulate write(2) that fails with a EPIPE","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-12-16T19:47:15Z","receivedAt":"2015-12-16T19:47:15Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wednesday, December 16, 2015, Johannes Schindelin\n<johannes.schindelin@gmx.de> wrote:\n> On Windows, when writing to a pipe fails, errno is always\n> EINVAL. However, Git expects it to be EPIPE.\n>\n> According to the documentation, there are two cases in which write()\n> triggers EINVAL: the buffer is NULL, or the length is odd but the mode\n> is 16-bit Unicode (the broken pipe is not mentioned as possible cause).\n> Git never sets the file mode to anything but binary, therefore we know\n> that errno should actually be EPIPE if it is EINVAL and the buffer is\n> not NULL.\n>\n> See https://msdn.microsoft.com/en-us/library/1570wh78.aspx for more\n> details.\n>\n> This works around t5571.11 failing with v2.6.4 on Windows.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n> diff --git a/compat/mingw.h b/compat/mingw.h\n> @@ -210,6 +210,24 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);\n> +static inline ssize_t mingw_write(int fd, const void *buf, size_t len)\n> +{\n> +       ssize_t result = write(fd, buf, len);\n> +\n> +       if (result < 0 && errno == EINVAL && buf) {\n\nHere, errno is EINVAL...\n\n> +               /* check if fd is a pipe */\n> +               HANDLE h = (HANDLE) _get_osfhandle(fd);\n> +               if (GetFileType(h) == FILE_TYPE_PIPE)\n> +                       errno = EPIPE;\n> +               else\n> +                       errno = EINVAL;\n\nDoes any of the code between the outer 'if' and this point clobber\nerrno, or are you merely assigning EINVAL for robustness against\nfuture changes?\n\n> +       }\n> +\n> +       return result;\n> +}\n> +\n> +#define write mingw_write\n> +\n> --\n> 2.6.3.windows.1.300.g1c25e49\n"},{"id":"274602","messageId":"xmqqmvtacere.fsf@gitster.mtv.corp.google.com","threadId":"41019","inReplyTo":"CAPig+cQzCHtyVs47=ASs5V2BSV7gpVszbdTFydiRhnz3gtD2Qw@mail.gmail.com","subject":"Re: [PATCH] mingw: emulate write(2) that fails with a EPIPE","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T20:36:21Z","receivedAt":"2015-12-16T20:36:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n>> +       if (result < 0 && errno == EINVAL && buf) {\n>\n> Here, errno is EINVAL...\n>\n>> +               /* check if fd is a pipe */\n>> +               HANDLE h = (HANDLE) _get_osfhandle(fd);\n>> +               if (GetFileType(h) == FILE_TYPE_PIPE)\n>> +                       errno = EPIPE;\n>> +               else\n>> +                       errno = EINVAL;\n>\n> Does any of the code between the outer 'if' and this point clobber\n> errno, or are you merely assigning EINVAL for robustness against\n> future changes?\n\nI do think it is a good idea to reassign 'errno' here to stress on\nthe fact that we return EPIPE only when we positively know that we\nwere reading from a pipe, and otherwise we won't change the original\nerrno at all.\n\nBut at the same time, if other things that are called before we\nfigure out if we were reading from a pipe could affect errno, I\nwonder if that is an indication of a bug--an error return from\nsystem functions that the code is not responding to.  For example,\ncan _get_osfhandle() fail and when it does what would we see?\nPerhaps NULL in h?\n"},{"id":"274659","messageId":"alpine.DEB.2.20.1512171035580.6483@virtualbox","threadId":"41019","inReplyTo":"CAPig+cQzCHtyVs47=ASs5V2BSV7gpVszbdTFydiRhnz3gtD2Qw@mail.gmail.com","subject":"Re: [PATCH] mingw: emulate write(2) that fails with a EPIPE","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2015-12-17T09:37:19Z","receivedAt":"2015-12-17T09:37:19Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Eric,\n\nOn Wed, 16 Dec 2015, Eric Sunshine wrote:\n\n> On Wednesday, December 16, 2015, Johannes Schindelin\n> <johannes.schindelin@gmx.de> wrote:\n> > diff --git a/compat/mingw.h b/compat/mingw.h\n> > @@ -210,6 +210,24 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);\n> > +static inline ssize_t mingw_write(int fd, const void *buf, size_t len)\n> > +{\n> > +       ssize_t result = write(fd, buf, len);\n> > +\n> > +       if (result < 0 && errno == EINVAL && buf) {\n> \n> Here, errno is EINVAL...\n> \n> > +               /* check if fd is a pipe */\n> > +               HANDLE h = (HANDLE) _get_osfhandle(fd);\n> > +               if (GetFileType(h) == FILE_TYPE_PIPE)\n> > +                       errno = EPIPE;\n> > +               else\n> > +                       errno = EINVAL;\n> \n> Does any of the code between the outer 'if' and this point clobber\n> errno, or are you merely assigning EINVAL for robustness against\n> future changes?\n\nYes, it is proofing the code against future changes. And TBH I did not\neven bother to check whether _get_osfhandle() or GetFileType() can modify\nthe errno value, since I *really* wanted to make sure that errno is either\nEPIPE or EINVAL in this execution path.\n\nCiao,\nDscho\n"},{"id":"274661","messageId":"alpine.DEB.2.20.1512171037310.6483@virtualbox","threadId":"41019","inReplyTo":"xmqq7fkedyx7.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH] mingw: emulate write(2) that fails with a EPIPE","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2015-12-17T09:39:43Z","receivedAt":"2015-12-17T09:39:43Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 16 Dec 2015, Junio C Hamano wrote:\n\n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> >  int mingw_fflush(FILE *stream);\n> >  #define fflush mingw_fflush\n> >  \n> > +static inline ssize_t mingw_write(int fd, const void *buf, size_t len)\n> > +{\n> > +\tssize_t result = write(fd, buf, len);\n> > +\n> > +\tif (result < 0 && errno == EINVAL && buf) {\n> > +\t\t/* check if fd is a pipe */\n> > +\t\tHANDLE h = (HANDLE) _get_osfhandle(fd);\n> > +\t\tif (GetFileType(h) == FILE_TYPE_PIPE)\n> > +\t\t\terrno = EPIPE;\n> > +\t\telse\n> > +\t\t\terrno = EINVAL;\n> > +\t}\n> > +\n> > +\treturn result;\n> > +}\n> > +\n> > +#define write mingw_write\n> > +\n> \n> It strikes me a bit strange to see this inlined compared to what\n> appears in the context.  Shouldn't the implementation be done in\n> compat/mingw.c like all others?\n\nMy intuition (which I honestly did not verify using performance tests) was\nthat write() is called *much* more often than, say, open(), and therefore\nI wanted to interfere as little as possible with the performance penalty.\nHence the choice of an inlined function as opposed to a non-optimizable\nincrement of the call chain.\n\nIf it bothers you a lot I will set aside time to perform performance\ntests.\n\nCiao,\nDscho\n"},{"id":"274671","messageId":"xmqqegelc9k8.fsf@gitster.mtv.corp.google.com","threadId":"41019","inReplyTo":"alpine.DEB.2.20.1512171037310.6483@virtualbox","subject":"Re: [PATCH] mingw: emulate write(2) that fails with a EPIPE","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-17T16:40:55Z","receivedAt":"2015-12-17T16:40:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> My intuition (which I honestly did not verify using performance tests) was\n> that write() is called *much* more often than, say, open(),...\n\nMy gut feeling agrees with yours, but I do not think the frequency\nat which write() is called should be the primary factor when you\ndecide to make its wrapper inlined.  Once you call write(2), you\nwill hit either the disk or the network doing I/O, and at that point\nI'd expect that the cost of making an extra layer of wrapper call\nwould be lost in the noise.  I'd worry a lot more about from how\nmany callsites write() is called---by inlining the extra code that\nis run only when the underlying write(2) returns an error to many\ncallsites, we would make the program as a whole bigger, and as the\nresult other code needs to be evicted out of the instruction cache,\nwhich also would hurt performance.\n"},{"id":"274674","messageId":"alpine.DEB.2.20.1512171807480.6483@virtualbox","threadId":"41019","inReplyTo":"xmqqegelc9k8.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH] mingw: emulate write(2) that fails with a EPIPE","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2015-12-17T17:08:08Z","receivedAt":"2015-12-17T17:08:08Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 17 Dec 2015, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > My intuition (which I honestly did not verify using performance tests) was\n> > that write() is called *much* more often than, say, open(),...\n> \n> My gut feeling agrees with yours, but I do not think the frequency\n> at which write() is called should be the primary factor when you\n> decide to make its wrapper inlined.  Once you call write(2), you\n> will hit either the disk or the network doing I/O, and at that point\n> I'd expect that the cost of making an extra layer of wrapper call\n> would be lost in the noise.  I'd worry a lot more about from how\n> many callsites write() is called---by inlining the extra code that\n> is run only when the underlying write(2) returns an error to many\n> callsites, we would make the program as a whole bigger, and as the\n> result other code needs to be evicted out of the instruction cache,\n> which also would hurt performance.\n\nThat argument convinced me. v2 coming shortly.\n\nCiao,\nDscho\n"},{"id":"274675","messageId":"ca357ac83a9990d6c88b637b76c6cc7f30d3f7be.1450372051.git.johannes.schindelin@gmx.de","threadId":"41019","inReplyTo":"01da36219c18373f8507e19035e141d7e56b2d18.1450267413.git.johannes.schindelin@gmx.de","subject":"[PATCH v2] mingw: emulate write(2) that fails with a EPIPE","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2015-12-17T17:08:15Z","receivedAt":"2015-12-17T17:08:15Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"On Windows, when writing to a pipe fails, errno is always\nEINVAL. However, Git expects it to be EPIPE.\n\nAccording to the documentation, there are two cases in which write()\ntriggers EINVAL: the buffer is NULL, or the length is odd but the mode\nis 16-bit Unicode (the broken pipe is not mentioned as possible cause).\nGit never sets the file mode to anything but binary, therefore we know\nthat errno should actually be EPIPE if it is EINVAL and the buffer is\nnot NULL.\n\nSee https://msdn.microsoft.com/en-us/library/1570wh78.aspx for more\ndetails.\n\nThis works around t5571.11 failing with v2.6.4 on Windows.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n compat/mingw.c | 17 +++++++++++++++++\n compat/mingw.h |  3 +++\n 2 files changed, 20 insertions(+)\n\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex 90bdb1e..5edea29 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -394,6 +394,23 @@ int mingw_fflush(FILE *stream)\n \treturn ret;\n }\n \n+#undef write\n+ssize_t mingw_write(int fd, const void *buf, size_t len)\n+{\n+\tssize_t result = write(fd, buf, len);\n+\n+\tif (result < 0 && errno == EINVAL && buf) {\n+\t\t/* check if fd is a pipe */\n+\t\tHANDLE h = (HANDLE) _get_osfhandle(fd);\n+\t\tif (GetFileType(h) == FILE_TYPE_PIPE)\n+\t\t\terrno = EPIPE;\n+\t\telse\n+\t\t\terrno = EINVAL;\n+\t}\n+\n+\treturn result;\n+}\n+\n int mingw_access(const char *filename, int mode)\n {\n \twchar_t wfilename[MAX_PATH];\ndiff --git a/compat/mingw.h b/compat/mingw.h\nindex 738865c..57ca477 100644\n--- a/compat/mingw.h\n+++ b/compat/mingw.h\n@@ -210,6 +210,9 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);\n int mingw_fflush(FILE *stream);\n #define fflush mingw_fflush\n \n+ssize_t mingw_write(int fd, const void *buf, size_t len);\n+#define write mingw_write\n+\n int mingw_access(const char *filename, int mode);\n #undef access\n #define access mingw_access\nInterdiff vs v1:\n\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex 90bdb1e..5edea29 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -394,6 +394,23 @@ int mingw_fflush(FILE *stream)\n \treturn ret;\n }\n \n+#undef write\n+ssize_t mingw_write(int fd, const void *buf, size_t len)\n+{\n+\tssize_t result = write(fd, buf, len);\n+\n+\tif (result < 0 && errno == EINVAL && buf) {\n+\t\t/* check if fd is a pipe */\n+\t\tHANDLE h = (HANDLE) _get_osfhandle(fd);\n+\t\tif (GetFileType(h) == FILE_TYPE_PIPE)\n+\t\t\terrno = EPIPE;\n+\t\telse\n+\t\t\terrno = EINVAL;\n+\t}\n+\n+\treturn result;\n+}\n+\n int mingw_access(const char *filename, int mode)\n {\n \twchar_t wfilename[MAX_PATH];\ndiff --git a/compat/mingw.h b/compat/mingw.h\nindex 2aca347..57ca477 100644\n--- a/compat/mingw.h\n+++ b/compat/mingw.h\n@@ -210,22 +210,7 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);\n int mingw_fflush(FILE *stream);\n #define fflush mingw_fflush\n \n-static inline ssize_t mingw_write(int fd, const void *buf, size_t len)\n-{\n-\tssize_t result = write(fd, buf, len);\n-\n-\tif (result < 0 && errno == EINVAL && buf) {\n-\t\t/* check if fd is a pipe */\n-\t\tHANDLE h = (HANDLE) _get_osfhandle(fd);\n-\t\tif (GetFileType(h) == FILE_TYPE_PIPE)\n-\t\t\terrno = EPIPE;\n-\t\telse\n-\t\t\terrno = EINVAL;\n-\t}\n-\n-\treturn result;\n-}\n-\n+ssize_t mingw_write(int fd, const void *buf, size_t len);\n #define write mingw_write\n \n int mingw_access(const char *filename, int mode);\n\n-- \n2.6.3.windows.1.300.g1c25e49\n"},{"id":"274683","messageId":"xmqqwpscc22e.fsf@gitster.mtv.corp.google.com","threadId":"41019","inReplyTo":"ca357ac83a9990d6c88b637b76c6cc7f30d3f7be.1450372051.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2] mingw: emulate write(2) that fails with a EPIPE","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-17T19:22:49Z","receivedAt":"2015-12-17T19:22:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n\n> On Windows, when writing to a pipe fails, errno is always\n> EINVAL. However, Git expects it to be EPIPE.\n>\n> According to the documentation, there are two cases in which write()\n> triggers EINVAL: the buffer is NULL, or the length is odd but the mode\n> is 16-bit Unicode (the broken pipe is not mentioned as possible cause).\n> Git never sets the file mode to anything but binary, therefore we know\n> that errno should actually be EPIPE if it is EINVAL and the buffer is\n> not NULL.\n>\n> See https://msdn.microsoft.com/en-us/library/1570wh78.aspx for more\n> details.\n>\n> This works around t5571.11 failing with v2.6.4 on Windows.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  compat/mingw.c | 17 +++++++++++++++++\n>  compat/mingw.h |  3 +++\n>  2 files changed, 20 insertions(+)\n>\n> diff --git a/compat/mingw.c b/compat/mingw.c\n> index 90bdb1e..5edea29 100644\n> --- a/compat/mingw.c\n> +++ b/compat/mingw.c\n> @@ -394,6 +394,23 @@ int mingw_fflush(FILE *stream)\n>  \treturn ret;\n>  }\n>  \n> +#undef write\n> +ssize_t mingw_write(int fd, const void *buf, size_t len)\n> +{\n> +\tssize_t result = write(fd, buf, len);\n> +\n> +\tif (result < 0 && errno == EINVAL && buf) {\n> +\t\t/* check if fd is a pipe */\n> +\t\tHANDLE h = (HANDLE) _get_osfhandle(fd);\n> +\t\tif (GetFileType(h) == FILE_TYPE_PIPE)\n> +\t\t\terrno = EPIPE;\n> +\t\telse\n> +\t\t\terrno = EINVAL;\n> +\t}\n> +\n> +\treturn result;\n> +}\n> +\n>  int mingw_access(const char *filename, int mode)\n>  {\n>  \twchar_t wfilename[MAX_PATH];\n> diff --git a/compat/mingw.h b/compat/mingw.h\n> index 738865c..57ca477 100644\n> --- a/compat/mingw.h\n> +++ b/compat/mingw.h\n> @@ -210,6 +210,9 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);\n>  int mingw_fflush(FILE *stream);\n>  #define fflush mingw_fflush\n>  \n> +ssize_t mingw_write(int fd, const void *buf, size_t len);\n> +#define write mingw_write\n> +\n>  int mingw_access(const char *filename, int mode);\n>  #undef access\n>  #define access mingw_access\n\n\nPLEASE DON'T DO THE BELOW TO THE SAME MESSAGE AS THE PATCH ITSELF.\n\"git apply\" would not read and understand the next line as a natural\nlanguage sentence for obvious reasons.\n\n> Interdiff vs v1:\n>\n> diff --git a/compat/mingw.c b/compat/mingw.c\n> index 90bdb1e..5edea29 100644\n> --- a/compat/mingw.c\n> +++ b/compat/mingw.c\n> @@ -394,6 +394,23 @@ int mingw_fflush(FILE *stream)\n>  \treturn ret;\n>  }\n>  \n> +#undef write\n> +ssize_t mingw_write(int fd, const void *buf, size_t len)\n> +{\n> +\tssize_t result = write(fd, buf, len);\n> +\n> +\tif (result < 0 && errno == EINVAL && buf) {\n> +\t\t/* check if fd is a pipe */\n> +\t\tHANDLE h = (HANDLE) _get_osfhandle(fd);\n> +\t\tif (GetFileType(h) == FILE_TYPE_PIPE)\n> +\t\t\terrno = EPIPE;\n> +\t\telse\n> +\t\t\terrno = EINVAL;\n> +\t}\n> +\n> +\treturn result;\n> +}\n> +\n>  int mingw_access(const char *filename, int mode)\n>  {\n>  \twchar_t wfilename[MAX_PATH];\n> diff --git a/compat/mingw.h b/compat/mingw.h\n> index 2aca347..57ca477 100644\n> --- a/compat/mingw.h\n> +++ b/compat/mingw.h\n> @@ -210,22 +210,7 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);\n>  int mingw_fflush(FILE *stream);\n>  #define fflush mingw_fflush\n>  \n> -static inline ssize_t mingw_write(int fd, const void *buf, size_t len)\n> -{\n> -\tssize_t result = write(fd, buf, len);\n> -\n> -\tif (result < 0 && errno == EINVAL && buf) {\n> -\t\t/* check if fd is a pipe */\n> -\t\tHANDLE h = (HANDLE) _get_osfhandle(fd);\n> -\t\tif (GetFileType(h) == FILE_TYPE_PIPE)\n> -\t\t\terrno = EPIPE;\n> -\t\telse\n> -\t\t\terrno = EINVAL;\n> -\t}\n> -\n> -\treturn result;\n> -}\n> -\n> +ssize_t mingw_write(int fd, const void *buf, size_t len);\n>  #define write mingw_write\n>  \n>  int mingw_access(const char *filename, int mode);\n"},{"id":"274720","messageId":"alpine.DEB.2.20.1512181709310.6483@virtualbox","threadId":"41019","inReplyTo":"xmqqwpscc22e.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2] mingw: emulate write(2) that fails with a EPIPE","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2015-12-18T16:10:48Z","receivedAt":"2015-12-18T16:10:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 17 Dec 2015, Junio C Hamano wrote:\n\n> PLEASE DON'T DO THE BELOW TO THE SAME MESSAGE AS THE PATCH ITSELF.\n> \"git apply\" would not read and understand the next line as a natural\n> language sentence for obvious reasons.\n> \n> Johannes Schindelin <johannes.schindelin@gmx.de> writes:\n> \n> > Interdiff vs v1:\n\nWhoops. This is an obvious bug in my patch series submission script. Will\nfix.\n\nSorry,\nDscho\n"},{"id":"274727","messageId":"5674732A.3050104@kdbg.org","threadId":"41019","inReplyTo":"ca357ac83a9990d6c88b637b76c6cc7f30d3f7be.1450372051.git.johannes.schindelin@gmx.de","subject":"Re: [PATCH v2] mingw: emulate write(2) that fails with a EPIPE","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2015-12-18T20:57:14Z","receivedAt":"2015-12-18T20:57:14Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 17.12.2015 um 18:08 schrieb Johannes Schindelin:\n> On Windows, when writing to a pipe fails, errno is always\n> EINVAL. However, Git expects it to be EPIPE.\n>\n> According to the documentation, there are two cases in which write()\n> triggers EINVAL: the buffer is NULL, or the length is odd but the mode\n> is 16-bit Unicode (the broken pipe is not mentioned as possible cause).\n> Git never sets the file mode to anything but binary, therefore we know\n> that errno should actually be EPIPE if it is EINVAL and the buffer is\n> not NULL.\n>\n> See https://msdn.microsoft.com/en-us/library/1570wh78.aspx for more\n> details.\n>\n> This works around t5571.11 failing with v2.6.4 on Windows.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>   compat/mingw.c | 17 +++++++++++++++++\n>   compat/mingw.h |  3 +++\n>   2 files changed, 20 insertions(+)\n>\n> diff --git a/compat/mingw.c b/compat/mingw.c\n> index 90bdb1e..5edea29 100644\n> --- a/compat/mingw.c\n> +++ b/compat/mingw.c\n> @@ -394,6 +394,23 @@ int mingw_fflush(FILE *stream)\n>   \treturn ret;\n>   }\n>\n> +#undef write\n> +ssize_t mingw_write(int fd, const void *buf, size_t len)\n> +{\n> +\tssize_t result = write(fd, buf, len);\n> +\n> +\tif (result < 0 && errno == EINVAL && buf) {\n> +\t\t/* check if fd is a pipe */\n> +\t\tHANDLE h = (HANDLE) _get_osfhandle(fd);\n> +\t\tif (GetFileType(h) == FILE_TYPE_PIPE)\n> +\t\t\terrno = EPIPE;\n> +\t\telse\n> +\t\t\terrno = EINVAL;\n> +\t}\n> +\n> +\treturn result;\n> +}\n> +\n>   int mingw_access(const char *filename, int mode)\n>   {\n>   \twchar_t wfilename[MAX_PATH];\n\nLooks good. I tested the patch, and it fixes the failure exposed by \nt5571.11.\n\nAcked-by: Johannes Sixt <j6t@kdbg.org>\n\nThanks!\n\n-- Hannes\n"},{"id":"274807","messageId":"xmqqr3ifhh4j.fsf@gitster.mtv.corp.google.com","threadId":"41019","inReplyTo":"5674732A.3050104@kdbg.org","subject":"Re: [PATCH v2] mingw: emulate write(2) that fails with a EPIPE","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-21T16:59:56Z","receivedAt":"2015-12-21T16:59:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n>> +#undef write\n>> +ssize_t mingw_write(int fd, const void *buf, size_t len)\n>> +{\n>> +\tssize_t result = write(fd, buf, len);\n>> +\n>> +\tif (result < 0 && errno == EINVAL && buf) {\n>> +\t\t/* check if fd is a pipe */\n>> +\t\tHANDLE h = (HANDLE) _get_osfhandle(fd);\n>> +\t\tif (GetFileType(h) == FILE_TYPE_PIPE)\n>> +\t\t\terrno = EPIPE;\n>> +\t\telse\n>> +\t\t\terrno = EINVAL;\n>> +\t}\n>> +\n>> +\treturn result;\n>> +}\n>> +\n>>   int mingw_access(const char *filename, int mode)\n>>   {\n>>   \twchar_t wfilename[MAX_PATH];\n>\n> Looks good. I tested the patch, and it fixes the failure exposed by\n> t5571.11.\n>\n> Acked-by: Johannes Sixt <j6t@kdbg.org>\n>\n> Thanks!\n\nThanks, both.\n"}]}