diff options
Diffstat (limited to 'compat')
-rw-r--r-- | compat/mingw.c | 131 | ||||
-rw-r--r-- | compat/mingw.h | 2 | ||||
-rw-r--r-- | compat/poll/poll.c | 6 | ||||
-rw-r--r-- | compat/poll/poll.h | 15 | ||||
-rw-r--r-- | compat/precompose_utf8.h | 3 | ||||
-rw-r--r-- | compat/vcbuild/README | 4 |
6 files changed, 146 insertions, 15 deletions
diff --git a/compat/mingw.c b/compat/mingw.c index 6ded1c859f..44264fe3fd 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -5,6 +5,7 @@ #include "../strbuf.h" #include "../run-command.h" #include "../cache.h" +#include "win32/lazyload.h" #define HCAST(type, handle) ((type)(intptr_t)handle) @@ -341,12 +342,74 @@ int mingw_mkdir(const char *path, int mode) return ret; } +/* + * Calling CreateFile() using FILE_APPEND_DATA and without FILE_WRITE_DATA + * is documented in [1] as opening a writable file handle in append mode. + * (It is believed that) this is atomic since it is maintained by the + * kernel unlike the O_APPEND flag which is racily maintained by the CRT. + * + * [1] https://docs.microsoft.com/en-us/windows/desktop/fileio/file-access-rights-constants + * + * This trick does not appear to work for named pipes. Instead it creates + * a named pipe client handle that cannot be written to. Callers should + * just use the regular _wopen() for them. (And since client handle gets + * bound to a unique server handle, it isn't really an issue.) + */ +static int mingw_open_append(wchar_t const *wfilename, int oflags, ...) +{ + HANDLE handle; + int fd; + DWORD create = (oflags & O_CREAT) ? OPEN_ALWAYS : OPEN_EXISTING; + + /* only these flags are supported */ + if ((oflags & ~O_CREAT) != (O_WRONLY | O_APPEND)) + return errno = ENOSYS, -1; + + /* + * FILE_SHARE_WRITE is required to permit child processes + * to append to the file. + */ + handle = CreateFileW(wfilename, FILE_APPEND_DATA, + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, create, FILE_ATTRIBUTE_NORMAL, NULL); + if (handle == INVALID_HANDLE_VALUE) + return errno = err_win_to_posix(GetLastError()), -1; + + /* + * No O_APPEND here, because the CRT uses it only to reset the + * file pointer to EOF before each write(); but that is not + * necessary (and may lead to races) for a file created with + * FILE_APPEND_DATA. + */ + fd = _open_osfhandle((intptr_t)handle, O_BINARY); + if (fd < 0) + CloseHandle(handle); + return fd; +} + +/* + * Does the pathname map to the local named pipe filesystem? + * That is, does it have a "//./pipe/" prefix? + */ +static int is_local_named_pipe_path(const char *filename) +{ + return (is_dir_sep(filename[0]) && + is_dir_sep(filename[1]) && + filename[2] == '.' && + is_dir_sep(filename[3]) && + !strncasecmp(filename+4, "pipe", 4) && + is_dir_sep(filename[8]) && + filename[9]); +} + int mingw_open (const char *filename, int oflags, ...) { + typedef int (*open_fn_t)(wchar_t const *wfilename, int oflags, ...); va_list args; unsigned mode; int fd; wchar_t wfilename[MAX_PATH]; + open_fn_t open_fn; va_start(args, oflags); mode = va_arg(args, int); @@ -355,9 +418,14 @@ int mingw_open (const char *filename, int oflags, ...) if (filename && !strcmp(filename, "/dev/null")) filename = "nul"; + if ((oflags & O_APPEND) && !is_local_named_pipe_path(filename)) + open_fn = mingw_open_append; + else + open_fn = _wopen; + if (xutftowcs_path(wfilename, filename) < 0) return -1; - fd = _wopen(wfilename, oflags, mode); + fd = open_fn(wfilename, oflags, mode); if (fd < 0 && (oflags & O_ACCMODE) != O_RDONLY && errno == EACCES) { DWORD attrs = GetFileAttributesW(wfilename); @@ -375,7 +443,7 @@ int mingw_open (const char *filename, int oflags, ...) * CREATE_ALWAYS flag of CreateFile()). */ if (fd < 0 && errno == EACCES) - fd = _wopen(wfilename, oflags & ~O_CREAT, mode); + fd = open_fn(wfilename, oflags & ~O_CREAT, mode); if (fd >= 0 && set_hidden_flag(wfilename, 1)) warning("could not mark '%s' as hidden.", filename); } @@ -1731,18 +1799,63 @@ int mingw_getpagesize(void) return si.dwAllocationGranularity; } +/* See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724435.aspx */ +enum EXTENDED_NAME_FORMAT { + NameDisplay = 3, + NameUserPrincipal = 8 +}; + +static char *get_extended_user_info(enum EXTENDED_NAME_FORMAT type) +{ + DECLARE_PROC_ADDR(secur32.dll, BOOL, GetUserNameExW, + enum EXTENDED_NAME_FORMAT, LPCWSTR, PULONG); + static wchar_t wbuffer[1024]; + DWORD len; + + if (!INIT_PROC_ADDR(GetUserNameExW)) + return NULL; + + len = ARRAY_SIZE(wbuffer); + if (GetUserNameExW(type, wbuffer, &len)) { + char *converted = xmalloc((len *= 3)); + if (xwcstoutf(converted, wbuffer, len) >= 0) + return converted; + free(converted); + } + + return NULL; +} + +char *mingw_query_user_email(void) +{ + return get_extended_user_info(NameUserPrincipal); +} + struct passwd *getpwuid(int uid) { + static unsigned initialized; static char user_name[100]; - static struct passwd p; + static struct passwd *p; + DWORD len; - DWORD len = sizeof(user_name); - if (!GetUserName(user_name, &len)) + if (initialized) + return p; + + len = sizeof(user_name); + if (!GetUserName(user_name, &len)) { + initialized = 1; return NULL; - p.pw_name = user_name; - p.pw_gecos = "unknown"; - p.pw_dir = NULL; - return &p; + } + + p = xmalloc(sizeof(*p)); + p->pw_name = user_name; + p->pw_gecos = get_extended_user_info(NameDisplay); + if (!p->pw_gecos) + p->pw_gecos = "unknown"; + p->pw_dir = NULL; + + initialized = 1; + return p; } static HANDLE timer_event; diff --git a/compat/mingw.h b/compat/mingw.h index 571019d0bd..f31dcff2be 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -424,6 +424,8 @@ static inline void convert_slashes(char *path) int mingw_offset_1st_component(const char *path); #define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' +extern char *mingw_query_user_email(void); +#define query_user_email mingw_query_user_email #if !defined(__MINGW64_VERSION_MAJOR) && (!defined(_MSC_VER) || _MSC_VER < 1800) #define PRIuMAX "I64u" #define PRId64 "I64d" diff --git a/compat/poll/poll.c b/compat/poll/poll.c index 7ed3fbbea1..ad5dcde439 100644 --- a/compat/poll/poll.c +++ b/compat/poll/poll.c @@ -29,9 +29,6 @@ #include <sys/types.h> -/* Specification. */ -#include <poll.h> - #include <errno.h> #include <limits.h> #include <assert.h> @@ -55,6 +52,9 @@ # include <unistd.h> #endif +/* Specification. */ +#include "poll.h" + #ifdef HAVE_SYS_IOCTL_H # include <sys/ioctl.h> #endif diff --git a/compat/poll/poll.h b/compat/poll/poll.h index cd1995292a..1e1597360f 100644 --- a/compat/poll/poll.h +++ b/compat/poll/poll.h @@ -21,6 +21,21 @@ #ifndef _GL_POLL_H #define _GL_POLL_H +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 +/* Vista has its own, socket-only poll() */ +#undef POLLIN +#undef POLLPRI +#undef POLLOUT +#undef POLLERR +#undef POLLHUP +#undef POLLNVAL +#undef POLLRDNORM +#undef POLLRDBAND +#undef POLLWRNORM +#undef POLLWRBAND +#define pollfd compat_pollfd +#endif + /* fake a poll(2) environment */ #define POLLIN 0x0001 /* any readable data available */ #define POLLPRI 0x0002 /* OOB/Urgent readable data */ diff --git a/compat/precompose_utf8.h b/compat/precompose_utf8.h index a94e7c4342..6f843d3e1a 100644 --- a/compat/precompose_utf8.h +++ b/compat/precompose_utf8.h @@ -1,4 +1,6 @@ #ifndef PRECOMPOSE_UNICODE_H +#define PRECOMPOSE_UNICODE_H + #include <sys/stat.h> #include <sys/types.h> #include <dirent.h> @@ -41,5 +43,4 @@ int precompose_utf8_closedir(PREC_DIR *dirp); #define DIR PREC_DIR #endif /* PRECOMPOSE_UNICODE_C */ -#define PRECOMPOSE_UNICODE_H #endif /* PRECOMPOSE_UNICODE_H */ diff --git a/compat/vcbuild/README b/compat/vcbuild/README index df8a6574c9..60fd873fe8 100644 --- a/compat/vcbuild/README +++ b/compat/vcbuild/README @@ -30,8 +30,8 @@ The Steps of Build Git with VS2008 the git operations. 3. Inside Git's directory run the command: - make common-cmds.h - to generate the common-cmds.h file needed to compile git. + make command-list.h + to generate the command-list.h file needed to compile git. 4. Then either build Git with the GNU Make Makefile in the Git projects root |