diff options
Diffstat (limited to 'compat')
-rw-r--r-- | compat/cygwin.c | 20 | ||||
-rw-r--r-- | compat/mingw.c | 23 |
2 files changed, 36 insertions, 7 deletions
diff --git a/compat/cygwin.c b/compat/cygwin.c index 423ff20b0e..ebac148392 100644 --- a/compat/cygwin.c +++ b/compat/cygwin.c @@ -91,13 +91,24 @@ static int cygwin_stat(const char *path, struct stat *buf) * functions should be used. The choice is determined by core.ignorecygwinfstricks. * Reading this option is not always possible immediately as git_dir may be * not be set yet. So until it is set, use cygwin lstat/stat functions. + * However, if core.filemode is set, we must use the Cygwin posix + * stat/lstat as the Windows stat fuctions do not determine posix filemode. + * + * Note that git_cygwin_config() does NOT call git_default_config() and this + * is deliberate. Many commands read from config to establish initial + * values in variables and later tweak them from elsewhere (e.g. command line). + * init_stat() is called lazily on demand, typically much late in the program, + * and calling git_default_config() from here would break such variables. */ static int native_stat = 1; +static int core_filemode; static int git_cygwin_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "core.ignorecygwinfstricks")) native_stat = git_config_bool(var, value); + else if (!strcmp(var, "core.filemode")) + core_filemode = git_config_bool(var, value); return 0; } @@ -105,8 +116,13 @@ static int init_stat(void) { if (have_git_dir()) { git_config(git_cygwin_config, NULL); - cygwin_stat_fn = native_stat ? cygwin_stat : stat; - cygwin_lstat_fn = native_stat ? cygwin_lstat : lstat; + if (!core_filemode && native_stat) { + cygwin_stat_fn = cygwin_stat; + cygwin_lstat_fn = cygwin_lstat; + } else { + cygwin_stat_fn = stat; + cygwin_lstat_fn = lstat; + } return 0; } return 1; diff --git a/compat/mingw.c b/compat/mingw.c index 09858f6c59..3dbe6a77ff 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -536,12 +536,16 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, * would normally create a console window. But * since we'll be redirecting std streams, we do * not need the console. + * It is necessary to use DETACHED_PROCESS + * instead of CREATE_NO_WINDOW to make ssh + * recognize that it has no console. */ - flags = CREATE_NO_WINDOW; + flags = DETACHED_PROCESS; } else { /* There is already a console. If we specified - * CREATE_NO_WINDOW here, too, Windows would + * DETACHED_PROCESS here, too, Windows would * disassociate the child from the console. + * The same is true for CREATE_NO_WINDOW. * Go figure! */ flags = 0; @@ -815,6 +819,8 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz) #undef rename int mingw_rename(const char *pold, const char *pnew) { + DWORD attrs; + /* * Try native rename() first to get errno right. * It is based on MoveFile(), which cannot overwrite existing files. @@ -826,12 +832,19 @@ int mingw_rename(const char *pold, const char *pnew) if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) return 0; /* TODO: translate more errors */ - if (GetLastError() == ERROR_ACCESS_DENIED) { - DWORD attrs = GetFileAttributes(pnew); - if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { + if (GetLastError() == ERROR_ACCESS_DENIED && + (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) { + if (attrs & FILE_ATTRIBUTE_DIRECTORY) { errno = EISDIR; return -1; } + if ((attrs & FILE_ATTRIBUTE_READONLY) && + SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) { + if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) + return 0; + /* revert file attributes on failure */ + SetFileAttributes(pnew, attrs); + } } errno = EACCES; return -1; |