@@ -341,6 +341,19 @@ int mingw_mkdir(const char *path, int mode)
341
341
return ret ;
342
342
}
343
343
344
+ /*
345
+ * Calling CreateFile() using FILE_APPEND_DATA and without FILE_WRITE_DATA
346
+ * is documented in [1] as opening a writable file handle in append mode.
347
+ * (It is believed that) this is atomic since it is maintained by the
348
+ * kernel unlike the O_APPEND flag which is racily maintained by the CRT.
349
+ *
350
+ * [1] https://docs.microsoft.com/en-us/windows/desktop/fileio/file-access-rights-constants
351
+ *
352
+ * This trick does not appear to work for named pipes. Instead it creates
353
+ * a named pipe client handle that cannot be written to. Callers should
354
+ * just use the regular _wopen() for them. (And since client handle gets
355
+ * bound to a unique server handle, it isn't really an issue.)
356
+ */
344
357
static int mingw_open_append (wchar_t const * wfilename , int oflags , ...)
345
358
{
346
359
HANDLE handle ;
@@ -360,17 +373,34 @@ static int mingw_open_append(wchar_t const *wfilename, int oflags, ...)
360
373
NULL , create , FILE_ATTRIBUTE_NORMAL , NULL );
361
374
if (handle == INVALID_HANDLE_VALUE )
362
375
return errno = err_win_to_posix (GetLastError ()), -1 ;
376
+
363
377
/*
364
378
* No O_APPEND here, because the CRT uses it only to reset the
365
- * file pointer to EOF on write(); but that is not necessary
366
- * for a file created with FILE_APPEND_DATA.
379
+ * file pointer to EOF before each write(); but that is not
380
+ * necessary (and may lead to races) for a file created with
381
+ * FILE_APPEND_DATA.
367
382
*/
368
383
fd = _open_osfhandle ((intptr_t )handle , O_BINARY );
369
384
if (fd < 0 )
370
385
CloseHandle (handle );
371
386
return fd ;
372
387
}
373
388
389
+ /*
390
+ * Does the pathname map to the local named pipe filesystem?
391
+ * That is, does it have a "//./pipe/" prefix?
392
+ */
393
+ static int is_local_named_pipe_path (const char * filename )
394
+ {
395
+ return (is_dir_sep (filename [0 ]) &&
396
+ is_dir_sep (filename [1 ]) &&
397
+ filename [2 ] == '.' &&
398
+ is_dir_sep (filename [3 ]) &&
399
+ !strncasecmp (filename + 4 , "pipe" , 4 ) &&
400
+ is_dir_sep (filename [8 ]) &&
401
+ filename [9 ]);
402
+ }
403
+
374
404
int mingw_open (const char * filename , int oflags , ...)
375
405
{
376
406
typedef int (* open_fn_t )(wchar_t const * wfilename , int oflags , ...);
@@ -387,7 +417,7 @@ int mingw_open (const char *filename, int oflags, ...)
387
417
if (filename && !strcmp (filename , "/dev/null" ))
388
418
filename = "nul" ;
389
419
390
- if (oflags & O_APPEND )
420
+ if (( oflags & O_APPEND ) && ! is_local_named_pipe_path ( filename ) )
391
421
open_fn = mingw_open_append ;
392
422
else
393
423
open_fn = _wopen ;
0 commit comments