Skip to content

Commit

Permalink
Add config option windows.appendAtomically
Browse files Browse the repository at this point in the history
Atomic append on windows is only supported on local disk files, and it may
cause errors in other situations, e.g. network file system. If that is the
case, this config option should be used to turn atomic append off.

Co-Authored-By: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: 孙卓识 <sunzhuoshi@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
  • Loading branch information
sunzhuoshi and dscho committed Nov 22, 2024
1 parent fb525f5 commit c903912
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 3 deletions.
2 changes: 2 additions & 0 deletions Documentation/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -554,4 +554,6 @@ include::config/versionsort.txt[]

include::config/web.txt[]

include::config/windows.txt[]

include::config/worktree.txt[]
4 changes: 4 additions & 0 deletions Documentation/config/windows.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
windows.appendAtomically::
By default, append atomic API is used on windows. But it works only with
local disk files, if you're working on a network file system, you should
set it false to turn it off.
36 changes: 33 additions & 3 deletions compat/mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "gettext.h"
#define SECURITY_WIN32
#include <sspi.h>
#include "../repository.h"

#define HCAST(type, handle) ((type)(intptr_t)handle)

Expand Down Expand Up @@ -549,6 +550,7 @@ static int is_local_named_pipe_path(const char *filename)

int mingw_open (const char *filename, int oflags, ...)
{
static int append_atomically = -1;
typedef int (*open_fn_t)(wchar_t const *wfilename, int oflags, ...);
va_list args;
unsigned mode;
Expand All @@ -565,7 +567,16 @@ int mingw_open (const char *filename, int oflags, ...)
return -1;
}

if ((oflags & O_APPEND) && !is_local_named_pipe_path(filename))
/*
* Only set append_atomically to default value(1) when repo is initialized
* and fail to get config value
*/
if (append_atomically < 0 && the_repository && the_repository->commondir &&
git_config_get_bool("windows.appendatomically", &append_atomically))
append_atomically = 1;

if (append_atomically && (oflags & O_APPEND) &&
!is_local_named_pipe_path(filename))
open_fn = mingw_open_append;
else
open_fn = _wopen;
Expand Down Expand Up @@ -714,9 +725,28 @@ ssize_t mingw_write(int fd, const void *buf, size_t len)

/* check if fd is a pipe */
HANDLE h = (HANDLE) _get_osfhandle(fd);
if (GetFileType(h) != FILE_TYPE_PIPE)
if (GetFileType(h) != FILE_TYPE_PIPE) {
if (orig == EINVAL) {
wchar_t path[MAX_PATH];
DWORD ret = GetFinalPathNameByHandleW(h, path,
ARRAY_SIZE(path), 0);
UINT drive_type = ret > 0 && ret < ARRAY_SIZE(path) ?
GetDriveTypeW(path) : DRIVE_UNKNOWN;

/*
* The default atomic append causes such an error on
* network file systems, in such a case, it should be
* turned off via config.
*
* `drive_type` of UNC path: DRIVE_NO_ROOT_DIR
*/
if (DRIVE_NO_ROOT_DIR == drive_type || DRIVE_REMOTE == drive_type)
warning("invalid write operation detected; you may try:\n"
"\n\tgit config windows.appendAtomically false");
}

errno = orig;
else if (orig == EINVAL)
} else if (orig == EINVAL)
errno = EPIPE;
else {
DWORD buf_size;
Expand Down

0 comments on commit c903912

Please sign in to comment.