Skip to content

Commit d18d09b

Browse files
committed
Merge branch 'js/mingw-o-append'
Among the three codepaths we use O_APPEND to open a file for appending, one used for writing GIT_TRACE output requires O_APPEND implementation that behaves sensibly when multiple processes are writing to the same file. POSIX emulation used in the Windows port has been updated to improve in this area. * js/mingw-o-append: mingw: enable atomic O_APPEND
2 parents 0c54cda + d641097 commit d18d09b

File tree

1 file changed

+39
-2
lines changed

1 file changed

+39
-2
lines changed

compat/mingw.c

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,12 +341,44 @@ int mingw_mkdir(const char *path, int mode)
341341
return ret;
342342
}
343343

344+
static int mingw_open_append(wchar_t const *wfilename, int oflags, ...)
345+
{
346+
HANDLE handle;
347+
int fd;
348+
DWORD create = (oflags & O_CREAT) ? OPEN_ALWAYS : OPEN_EXISTING;
349+
350+
/* only these flags are supported */
351+
if ((oflags & ~O_CREAT) != (O_WRONLY | O_APPEND))
352+
return errno = ENOSYS, -1;
353+
354+
/*
355+
* FILE_SHARE_WRITE is required to permit child processes
356+
* to append to the file.
357+
*/
358+
handle = CreateFileW(wfilename, FILE_APPEND_DATA,
359+
FILE_SHARE_WRITE | FILE_SHARE_READ,
360+
NULL, create, FILE_ATTRIBUTE_NORMAL, NULL);
361+
if (handle == INVALID_HANDLE_VALUE)
362+
return errno = err_win_to_posix(GetLastError()), -1;
363+
/*
364+
* 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.
367+
*/
368+
fd = _open_osfhandle((intptr_t)handle, O_BINARY);
369+
if (fd < 0)
370+
CloseHandle(handle);
371+
return fd;
372+
}
373+
344374
int mingw_open (const char *filename, int oflags, ...)
345375
{
376+
typedef int (*open_fn_t)(wchar_t const *wfilename, int oflags, ...);
346377
va_list args;
347378
unsigned mode;
348379
int fd;
349380
wchar_t wfilename[MAX_PATH];
381+
open_fn_t open_fn;
350382

351383
va_start(args, oflags);
352384
mode = va_arg(args, int);
@@ -355,9 +387,14 @@ int mingw_open (const char *filename, int oflags, ...)
355387
if (filename && !strcmp(filename, "/dev/null"))
356388
filename = "nul";
357389

390+
if (oflags & O_APPEND)
391+
open_fn = mingw_open_append;
392+
else
393+
open_fn = _wopen;
394+
358395
if (xutftowcs_path(wfilename, filename) < 0)
359396
return -1;
360-
fd = _wopen(wfilename, oflags, mode);
397+
fd = open_fn(wfilename, oflags, mode);
361398

362399
if (fd < 0 && (oflags & O_ACCMODE) != O_RDONLY && errno == EACCES) {
363400
DWORD attrs = GetFileAttributesW(wfilename);
@@ -375,7 +412,7 @@ int mingw_open (const char *filename, int oflags, ...)
375412
* CREATE_ALWAYS flag of CreateFile()).
376413
*/
377414
if (fd < 0 && errno == EACCES)
378-
fd = _wopen(wfilename, oflags & ~O_CREAT, mode);
415+
fd = open_fn(wfilename, oflags & ~O_CREAT, mode);
379416
if (fd >= 0 && set_hidden_flag(wfilename, 1))
380417
warning("could not mark '%s' as hidden.", filename);
381418
}

0 commit comments

Comments
 (0)