diff options
Diffstat (limited to 'compat')
-rw-r--r-- | compat/apple-common-crypto.h | 20 | ||||
-rw-r--r-- | compat/basename.c | 66 | ||||
-rw-r--r-- | compat/bswap.h | 5 | ||||
-rw-r--r-- | compat/hstrerror.c | 2 | ||||
-rw-r--r-- | compat/inet_ntop.c | 6 | ||||
-rw-r--r-- | compat/mingw.c | 286 | ||||
-rw-r--r-- | compat/mingw.h | 88 | ||||
-rw-r--r-- | compat/nedmalloc/malloc.c.h | 7 | ||||
-rw-r--r-- | compat/nedmalloc/nedmalloc.c | 24 | ||||
-rw-r--r-- | compat/poll/poll.c | 18 | ||||
-rw-r--r-- | compat/precompose_utf8.c | 26 | ||||
-rw-r--r-- | compat/precompose_utf8.h | 2 | ||||
-rw-r--r-- | compat/qsort.c | 2 | ||||
-rw-r--r-- | compat/qsort_s.c | 69 | ||||
-rw-r--r-- | compat/regex/regcomp.c | 4 | ||||
-rw-r--r-- | compat/regex/regex.c | 1 | ||||
-rw-r--r-- | compat/setenv.c | 2 | ||||
-rw-r--r-- | compat/sha1-chunked.c | 19 | ||||
-rw-r--r-- | compat/sha1-chunked.h | 2 | ||||
-rw-r--r-- | compat/snprintf.c | 2 | ||||
-rw-r--r-- | compat/strdup.c | 11 | ||||
-rw-r--r-- | compat/terminal.c | 2 | ||||
-rw-r--r-- | compat/vcbuild/include/unistd.h | 4 | ||||
-rw-r--r-- | compat/win32/pthread.h | 16 | ||||
-rw-r--r-- | compat/win32/syslog.c | 10 | ||||
-rw-r--r-- | compat/win32mmap.c | 31 | ||||
-rw-r--r-- | compat/winansi.c | 207 |
27 files changed, 690 insertions, 242 deletions
diff --git a/compat/apple-common-crypto.h b/compat/apple-common-crypto.h index c8b9b0e1a6..11727f3e1e 100644 --- a/compat/apple-common-crypto.h +++ b/compat/apple-common-crypto.h @@ -3,12 +3,18 @@ #define HEADER_HMAC_H #define HEADER_SHA_H #include <CommonCrypto/CommonHMAC.h> -#define HMAC_CTX CCHmacContext -#define HMAC_Init(hmac, key, len, algo) CCHmacInit(hmac, algo, key, len) -#define HMAC_Update CCHmacUpdate -#define HMAC_Final(hmac, hash, ptr) CCHmacFinal(hmac, hash) -#define HMAC_CTX_cleanup(ignore) #define EVP_md5(...) kCCHmacAlgMD5 +/* CCHmac doesn't take md_len and the return type is void */ +#define HMAC git_CC_HMAC +static inline unsigned char *git_CC_HMAC(CCHmacAlgorithm alg, + const void *key, int key_len, + const unsigned char *data, size_t data_len, + unsigned char *md, unsigned int *md_len) +{ + CCHmac(alg, key, key_len, data, data_len, md); + return md; +} + #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 #define APPLE_LION_OR_NEWER #include <Security/Security.h> @@ -16,6 +22,10 @@ #undef TYPE_BOOL #endif +#ifndef SHA1_MAX_BLOCK_SIZE +#error Using Apple Common Crypto library requires setting SHA1_MAX_BLOCK_SIZE +#endif + #ifdef APPLE_LION_OR_NEWER #define git_CC_error_check(pattern, err) \ do { \ diff --git a/compat/basename.c b/compat/basename.c index d8f8a3c6dc..96bd9533b4 100644 --- a/compat/basename.c +++ b/compat/basename.c @@ -1,15 +1,71 @@ #include "../git-compat-util.h" +#include "../strbuf.h" /* Adapted from libiberty's basename.c. */ char *gitbasename (char *path) { const char *base; - /* Skip over the disk name in MSDOS pathnames. */ - if (has_dos_drive_prefix(path)) - path += 2; + + if (path) + skip_dos_drive_prefix(&path); + + if (!path || !*path) + return "."; + for (base = path; *path; path++) { - if (is_dir_sep(*path)) - base = path + 1; + if (!is_dir_sep(*path)) + continue; + do { + path++; + } while (is_dir_sep(*path)); + if (*path) + base = path; + else + while (--path != base && is_dir_sep(*path)) + *path = '\0'; } return (char *)base; } + +char *gitdirname(char *path) +{ + static struct strbuf buf = STRBUF_INIT; + char *p = path, *slash = NULL, c; + int dos_drive_prefix; + + if (!p) + return "."; + + if ((dos_drive_prefix = skip_dos_drive_prefix(&p)) && !*p) + goto dot; + + /* + * POSIX.1-2001 says dirname("/") should return "/", and dirname("//") + * should return "//", but dirname("///") should return "/" again. + */ + if (is_dir_sep(*p)) { + if (!p[1] || (is_dir_sep(p[1]) && !p[2])) + return path; + slash = ++p; + } + while ((c = *(p++))) + if (is_dir_sep(c)) { + char *tentative = p - 1; + + /* POSIX.1-2001 says to ignore trailing slashes */ + while (is_dir_sep(*p)) + p++; + if (*p) + slash = tentative; + } + + if (slash) { + *slash = '\0'; + return path; + } + +dot: + strbuf_reset(&buf); + strbuf_addf(&buf, "%.*s.", dos_drive_prefix, path); + return buf.buf; +} diff --git a/compat/bswap.h b/compat/bswap.h index 7fed637ed0..d47c003544 100644 --- a/compat/bswap.h +++ b/compat/bswap.h @@ -149,11 +149,12 @@ static inline uint64_t git_bswap64(uint64_t x) * and is faster on architectures with memory alignment issues. */ -#if defined(__i386__) || defined(__x86_64__) || \ +#if !defined(NO_UNALIGNED_LOADS) && ( \ + defined(__i386__) || defined(__x86_64__) || \ defined(_M_IX86) || defined(_M_X64) || \ defined(__ppc__) || defined(__ppc64__) || \ defined(__powerpc__) || defined(__powerpc64__) || \ - defined(__s390__) || defined(__s390x__) + defined(__s390__) || defined(__s390x__)) #define get_be16(p) ntohs(*(unsigned short *)(p)) #define get_be32(p) ntohl(*(unsigned int *)(p)) diff --git a/compat/hstrerror.c b/compat/hstrerror.c index 069c555da4..b85a2fa956 100644 --- a/compat/hstrerror.c +++ b/compat/hstrerror.c @@ -16,6 +16,6 @@ const char *githstrerror(int err) case TRY_AGAIN: return "Non-authoritative \"host not found\", or SERVERFAIL"; } - sprintf(buffer, "Name resolution error %d", err); + snprintf(buffer, sizeof(buffer), "Name resolution error %d", err); return buffer; } diff --git a/compat/inet_ntop.c b/compat/inet_ntop.c index 90b7cc45f3..68307262be 100644 --- a/compat/inet_ntop.c +++ b/compat/inet_ntop.c @@ -53,11 +53,11 @@ inet_ntop4(const u_char *src, char *dst, size_t size) nprinted = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); if (nprinted < 0) return (NULL); /* we assume "errno" was set by "snprintf()" */ - if ((size_t)nprinted > size) { + if ((size_t)nprinted >= size) { errno = ENOSPC; return (NULL); } - strcpy(dst, tmp); + strlcpy(dst, tmp, size); return (dst); } @@ -154,7 +154,7 @@ inet_ntop6(const u_char *src, char *dst, size_t size) errno = ENOSPC; return (NULL); } - strcpy(dst, tmp); + strlcpy(dst, tmp, size); return (dst); } #endif diff --git a/compat/mingw.c b/compat/mingw.c index 70f3191a4f..fe0e3ccd24 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -6,6 +6,8 @@ #include "../run-command.h" #include "../cache.h" +#define HCAST(type, handle) ((type)(intptr_t)handle) + static const int delay[] = { 0, 1, 10, 20, 40 }; int err_win_to_posix(DWORD winerr) @@ -284,6 +286,49 @@ int mingw_rmdir(const char *pathname) return ret; } +static inline int needs_hiding(const char *path) +{ + const char *basename; + + if (hide_dotfiles == HIDE_DOTFILES_FALSE) + return 0; + + /* We cannot use basename(), as it would remove trailing slashes */ + mingw_skip_dos_drive_prefix((char **)&path); + if (!*path) + return 0; + + for (basename = path; *path; path++) + if (is_dir_sep(*path)) { + do { + path++; + } while (is_dir_sep(*path)); + /* ignore trailing slashes */ + if (*path) + basename = path; + } + + if (hide_dotfiles == HIDE_DOTFILES_TRUE) + return *basename == '.'; + + assert(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY); + return !strncasecmp(".git", basename, 4) && + (!basename[4] || is_dir_sep(basename[4])); +} + +static int set_hidden_flag(const wchar_t *path, int set) +{ + DWORD original = GetFileAttributesW(path), modified; + if (set) + modified = original | FILE_ATTRIBUTE_HIDDEN; + else + modified = original & ~FILE_ATTRIBUTE_HIDDEN; + if (original == modified || SetFileAttributesW(path, modified)) + return 0; + errno = err_win_to_posix(GetLastError()); + return -1; +} + int mingw_mkdir(const char *path, int mode) { int ret; @@ -291,6 +336,8 @@ int mingw_mkdir(const char *path, int mode) if (xutftowcs_path(wpath, path) < 0) return -1; ret = _wmkdir(wpath); + if (!ret && needs_hiding(path)) + return set_hidden_flag(wpath, 1); return ret; } @@ -317,6 +364,21 @@ int mingw_open (const char *filename, int oflags, ...) if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) errno = EISDIR; } + if ((oflags & O_CREAT) && needs_hiding(filename)) { + /* + * Internally, _wopen() uses the CreateFile() API which errors + * out with an ERROR_ACCESS_DENIED if CREATE_ALWAYS was + * specified and an already existing file's attributes do not + * match *exactly*. As there is no mode or flag we can set that + * would correspond to FILE_ATTRIBUTE_HIDDEN, let's just try + * again *without* the O_CREAT flag (that corresponds to the + * CREATE_ALWAYS flag of CreateFile()). + */ + if (fd < 0 && errno == EACCES) + fd = _wopen(wfilename, oflags & ~O_CREAT, mode); + if (fd >= 0 && set_hidden_flag(wfilename, 1)) + warning("could not mark '%s' as hidden.", filename); + } return fd; } @@ -348,6 +410,7 @@ int mingw_fgetc(FILE *stream) #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { + int hide = needs_hiding(filename); FILE *file; wchar_t wfilename[MAX_PATH], wotype[4]; if (filename && !strcmp(filename, "/dev/null")) @@ -355,12 +418,19 @@ FILE *mingw_fopen (const char *filename, const char *otype) if (xutftowcs_path(wfilename, filename) < 0 || xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0) return NULL; + if (hide && !access(filename, F_OK) && set_hidden_flag(wfilename, 0)) { + error("could not unhide %s", filename); + return NULL; + } file = _wfopen(wfilename, wotype); + if (file && hide && set_hidden_flag(wfilename, 1)) + warning("could not mark '%s' as hidden.", filename); return file; } FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) { + int hide = needs_hiding(filename); FILE *file; wchar_t wfilename[MAX_PATH], wotype[4]; if (filename && !strcmp(filename, "/dev/null")) @@ -368,7 +438,13 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) if (xutftowcs_path(wfilename, filename) < 0 || xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0) return NULL; + if (hide && !access(filename, F_OK) && set_hidden_flag(wfilename, 0)) { + error("could not unhide %s", filename); + return NULL; + } file = _wfreopen(wfilename, wotype, stream); + if (file && hide && set_hidden_flag(wfilename, 1)) + warning("could not mark '%s' as hidden.", filename); return file; } @@ -394,6 +470,23 @@ int mingw_fflush(FILE *stream) return ret; } +#undef write +ssize_t mingw_write(int fd, const void *buf, size_t len) +{ + ssize_t result = write(fd, buf, len); + + if (result < 0 && errno == EINVAL && buf) { + /* check if fd is a pipe */ + HANDLE h = (HANDLE) _get_osfhandle(fd); + if (GetFileType(h) == FILE_TYPE_PIPE) + errno = EPIPE; + else + errno = EINVAL; + } + + return result; +} + int mingw_access(const char *filename, int mode) { wchar_t wfilename[MAX_PATH]; @@ -435,6 +528,39 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) return (time_t)(filetime_to_hnsec(ft) / 10000000); } +/** + * Verifies that safe_create_leading_directories() would succeed. + */ +static int has_valid_directory_prefix(wchar_t *wfilename) +{ + int n = wcslen(wfilename); + + while (n > 0) { + wchar_t c = wfilename[--n]; + DWORD attributes; + + if (!is_dir_sep(c)) + continue; + + wfilename[n] = L'\0'; + attributes = GetFileAttributesW(wfilename); + wfilename[n] = c; + if (attributes == FILE_ATTRIBUTE_DIRECTORY || + attributes == FILE_ATTRIBUTE_DEVICE) + return 1; + if (attributes == INVALID_FILE_ATTRIBUTES) + switch (GetLastError()) { + case ERROR_PATH_NOT_FOUND: + continue; + case ERROR_FILE_NOT_FOUND: + /* This implies parent directory exists. */ + return 1; + } + return 0; + } + return 1; +} + /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In * this case, we strip the trailing slashes and stat again. @@ -495,6 +621,12 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf) case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break; + case ERROR_PATH_NOT_FOUND: + if (!has_valid_directory_prefix(wfilename)) { + errno = ENOTDIR; + break; + } + /* fallthru */ default: errno = ENOENT; break; @@ -674,14 +806,14 @@ int pipe(int filedes[2]) errno = err_win_to_posix(GetLastError()); return -1; } - filedes[0] = _open_osfhandle((int)h[0], O_NOINHERIT); + filedes[0] = _open_osfhandle(HCAST(int, h[0]), O_NOINHERIT); if (filedes[0] < 0) { CloseHandle(h[0]); CloseHandle(h[1]); return -1; } - filedes[1] = _open_osfhandle((int)h[1], O_NOINHERIT); - if (filedes[0] < 0) { + filedes[1] = _open_osfhandle(HCAST(int, h[1]), O_NOINHERIT); + if (filedes[1] < 0) { close(filedes[0]); CloseHandle(h[1]); return -1; @@ -705,15 +837,12 @@ struct tm *localtime_r(const time_t *timep, struct tm *result) char *mingw_getcwd(char *pointer, int len) { - int i; wchar_t wpointer[MAX_PATH]; if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer))) return NULL; if (xwcstoutf(pointer, wpointer, len) < 0) return NULL; - for (i = 0; pointer[i]; i++) - if (pointer[i] == '\\') - pointer[i] = '/'; + convert_slashes(pointer); return pointer; } @@ -752,7 +881,7 @@ static const char *quote_arg(const char *arg) return arg; /* insert \ where necessary */ - d = q = xmalloc(len+n+3); + d = q = xmalloc(st_add3(len, n, 3)); *d++ = '"'; while (*arg) { if (*arg == '"') @@ -832,10 +961,12 @@ static char **get_path_split(void) ++n; } } - if (!n) + if (!n) { + free(envpath); return NULL; + } - path = xmalloc((n+1)*sizeof(char *)); + ALLOC_ARRAY(path, n + 1); p = envpath; i = 0; do { @@ -920,7 +1051,7 @@ static wchar_t *make_environment_block(char **deltaenv) i++; /* copy the environment, leaving space for changes */ - tmpenv = xmalloc((size + i) * sizeof(char*)); + ALLOC_ARRAY(tmpenv, size + i); memcpy(tmpenv, environ, size * sizeof(char*)); /* merge supplied environment changes into the temporary environment */ @@ -1011,7 +1142,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen free(quoted); } - wargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t)); + ALLOC_ARRAY(wargs, st_add(st_mult(2, args.len), 1)); xutftowcs(wargs, args.buf, 2 * args.len + 1); strbuf_release(&args); @@ -1110,7 +1241,7 @@ static int try_shell_exec(const char *cmd, char *const *argv) int argc = 0; const char **argv2; while (argv[argc]) argc++; - argv2 = xmalloc(sizeof(*argv) * (argc+1)); + ALLOC_ARRAY(argv2, argc + 1); argv2[0] = (char *)cmd; /* full path to the script file */ memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc); pid = mingw_spawnv(prog, argv2, 1); @@ -1584,7 +1715,12 @@ repeat: if (gle == ERROR_ACCESS_DENIED && (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) { if (attrs & FILE_ATTRIBUTE_DIRECTORY) { - errno = EISDIR; + DWORD attrsold = GetFileAttributesW(wpold); + if (attrsold == INVALID_FILE_ATTRIBUTES || + !(attrsold & FILE_ATTRIBUTE_DIRECTORY)) + errno = EISDIR; + else if (!_wrmdir(wpnew)) + goto repeat; return -1; } if ((attrs & FILE_ATTRIBUTE_READONLY) && @@ -1796,47 +1932,6 @@ int mingw_raise(int sig) } } - -static const char *make_backslash_path(const char *path) -{ - static char buf[PATH_MAX + 1]; - char *c; - - if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) - die("Too long path: %.*s", 60, path); - - for (c = buf; *c; c++) { - if (*c == '/') - *c = '\\'; - } - return buf; -} - -void mingw_open_html(const char *unixpath) -{ - const char *htmlpath = make_backslash_path(unixpath); - typedef HINSTANCE (WINAPI *T)(HWND, const char *, - const char *, const char *, const char *, INT); - T ShellExecute; - HMODULE shell32; - int r; - - shell32 = LoadLibrary("shell32.dll"); - if (!shell32) - die("cannot load shell32.dll"); - ShellExecute = (T)GetProcAddress(shell32, "ShellExecuteA"); - if (!ShellExecute) - die("cannot run browser"); - - printf("Launching default browser to display HTML ...\n"); - r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL); - FreeLibrary(shell32); - /* see the MSDN documentation referring to the result codes here */ - if (r <= 32) { - die("failed to launch browser for %.*s", MAX_PATH, unixpath); - } -} - int link(const char *oldpath, const char *newpath) { typedef BOOL (WINAPI *T)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); @@ -1915,28 +2010,31 @@ pid_t waitpid(pid_t pid, int *status, int options) return -1; } +int mingw_skip_dos_drive_prefix(char **path) +{ + int ret = has_dos_drive_prefix(*path); + *path += ret; + return ret; +} + int mingw_offset_1st_component(const char *path) { - int offset = 0; - if (has_dos_drive_prefix(path)) - offset = 2; + char *pos = (char *)path; /* unc paths */ - else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) { - + if (!skip_dos_drive_prefix(&pos) && + is_dir_sep(pos[0]) && is_dir_sep(pos[1])) { /* skip server name */ - char *pos = strpbrk(path + 2, "\\/"); + pos = strpbrk(pos + 2, "\\/"); if (!pos) return 0; /* Error: malformed unc path */ do { pos++; } while (*pos && !is_dir_sep(*pos)); - - offset = pos - path; } - return offset + is_dir_sep(path[offset]); + return pos + is_dir_sep(*pos) - path; } int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen) @@ -2024,6 +2122,35 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen) return -1; } +static void setup_windows_environment(void) +{ + char *tmp = getenv("TMPDIR"); + + /* on Windows it is TMP and TEMP */ + if (!tmp) { + if (!(tmp = getenv("TMP"))) + tmp = getenv("TEMP"); + if (tmp) { + setenv("TMPDIR", tmp, 1); + tmp = getenv("TMPDIR"); + } + } + + if (tmp) { + /* + * Convert all dir separators to forward slashes, + * to help shell commands called from the Git + * executable (by not mistaking the dir separators + * for escape characters). + */ + convert_slashes(tmp); + } + + /* simulate TERM to enable auto-color (see color.c) */ + if (!getenv("TERM")) + setenv("TERM", "cygwin", 1); +} + /* * Disable MSVCRT command line wildcard expansion (__getmainargs called from * mingw startup code, see init.c in mingw runtime). @@ -2037,7 +2164,7 @@ typedef struct { extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob, _startupinfo *si); -static NORETURN void die_startup() +static NORETURN void die_startup(void) { fputs("fatal: not enough memory for initialization", stderr); exit(128); @@ -2057,7 +2184,7 @@ static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len) return memcpy(malloc_startup(len), buffer, len); } -void mingw_startup() +void mingw_startup(void) { int i, maxlen, argc; char *buffer; @@ -2102,19 +2229,7 @@ void mingw_startup() qsort(environ, i, sizeof(char*), compareenv); /* fix Windows specific environment settings */ - - /* on Windows it is TMP and TEMP */ - if (!mingw_getenv("TMPDIR")) { - const char *tmp = mingw_getenv("TMP"); - if (!tmp) - tmp = mingw_getenv("TEMP"); - if (tmp) - setenv("TMPDIR", tmp, 1); - } - - /* simulate TERM to enable auto-color (see color.c) */ - if (!getenv("TERM")) - setenv("TERM", "cygwin", 1); + setup_windows_environment(); /* initialize critical section for waitpid pinfo_t list */ InitializeCriticalSection(&pinfo_cs); @@ -2128,3 +2243,16 @@ void mingw_startup() /* initialize Unicode console */ winansi_init(); } + +int uname(struct utsname *buf) +{ + unsigned v = (unsigned)GetVersion(); + memset(buf, 0, sizeof(*buf)); + xsnprintf(buf->sysname, sizeof(buf->sysname), "Windows"); + xsnprintf(buf->release, sizeof(buf->release), + "%u.%u", v & 0xff, (v >> 8) & 0xff); + /* assuming NT variants only.. */ + xsnprintf(buf->version, sizeof(buf->version), + "%u", (v >> 16) & 0x7fff); + return 0; +} diff --git a/compat/mingw.h b/compat/mingw.h index 5e499cfb71..e03aecfe2e 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -1,27 +1,43 @@ +#ifdef __MINGW64_VERSION_MAJOR +#include <stdint.h> +#include <wchar.h> +typedef _sigset_t sigset_t; +#endif #include <winsock2.h> #include <ws2tcpip.h> +/* MinGW-w64 reports to have flockfile, but it does not actually have it. */ +#ifdef __MINGW64_VERSION_MAJOR +#undef _POSIX_THREAD_SAFE_FUNCTIONS +#endif + /* * things that are not available in header files */ -typedef int pid_t; typedef int uid_t; typedef int socklen_t; +#ifndef __MINGW64_VERSION_MAJOR +typedef int pid_t; #define hstrerror strerror +#endif #define S_IFLNK 0120000 /* Symbolic link */ #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 +#ifndef S_IRWXG #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 #define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) +#endif +#ifndef S_IRWXO #define S_IROTH 0 #define S_IWOTH 0 #define S_IXOTH 0 #define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#endif #define S_ISUID 0004000 #define S_ISGID 0002000 @@ -51,12 +67,19 @@ typedef int socklen_t; #define F_SETFD 2 #define FD_CLOEXEC 0x1 +#if !defined O_CLOEXEC && defined O_NOINHERIT +#define O_CLOEXEC O_NOINHERIT +#endif + #ifndef EAFNOSUPPORT #define EAFNOSUPPORT WSAEAFNOSUPPORT #endif #ifndef ECONNABORTED #define ECONNABORTED WSAECONNABORTED #endif +#ifndef ENOTSOCK +#define ENOTSOCK WSAENOTSOCK +#endif struct passwd { char *pw_name; @@ -76,6 +99,14 @@ struct itimerval { }; #define ITIMER_REAL 0 +struct utsname { + char sysname[16]; + char nodename[1]; + char release[16]; + char version[16]; + char machine[1]; +}; + /* * sanitize preprocessor namespace polluted by Windows headers defining * macros which collide with git local versions @@ -92,14 +123,14 @@ static inline int symlink(const char *oldpath, const char *newpath) { errno = ENOSYS; return -1; } static inline int fchmod(int fildes, mode_t mode) { errno = ENOSYS; return -1; } +#ifndef __MINGW64_VERSION_MAJOR static inline pid_t fork(void) { errno = ENOSYS; return -1; } +#endif static inline unsigned int alarm(unsigned int seconds) { return 0; } static inline int fsync(int fd) { return _commit(fd); } -static inline pid_t getppid(void) -{ return 1; } static inline void sync(void) {} static inline uid_t getuid(void) @@ -118,9 +149,16 @@ static inline int fcntl(int fd, int cmd, ...) #define sigemptyset(x) (void)0 static inline int sigaddset(sigset_t *set, int signum) { return 0; } +#define SIG_BLOCK 0 #define SIG_UNBLOCK 0 static inline int sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { return 0; } +static inline pid_t getppid(void) +{ return 1; } +static inline pid_t getpgid(pid_t pid) +{ return pid == 0 ? getpid() : pid; } +static inline pid_t tcgetpgrp(int fd) +{ return getpid(); } /* * simple adaptors @@ -164,13 +202,16 @@ int pipe(int filedes[2]); unsigned int sleep (unsigned int seconds); int mkstemp(char *template); int gettimeofday(struct timeval *tv, void *tz); +#ifndef __MINGW64_VERSION_MAJOR struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime_r(const time_t *timep, struct tm *result); +#endif int getpagesize(void); /* defined in MinGW's libgcc.a */ struct passwd *getpwuid(uid_t uid); int setitimer(int type, struct itimerval *in, struct itimerval *out); int sigaction(int sig, struct sigaction *in, struct sigaction *out); int link(const char *oldpath, const char *newpath); +int uname(struct utsname *buf); /* * replacements of existing functions @@ -197,6 +238,9 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream); int mingw_fflush(FILE *stream); #define fflush mingw_fflush +ssize_t mingw_write(int fd, const void *buf, size_t len); +#define write mingw_write + int mingw_access(const char *filename, int mode); #undef access #define access mingw_access @@ -285,8 +329,10 @@ static inline int getrlimit(int resource, struct rlimit *rlp) /* * Use mingw specific stat()/lstat()/fstat() implementations on Windows. */ +#ifndef __MINGW64_VERSION_MAJOR #define off_t off64_t #define lseek _lseeki64 +#endif /* use struct stat with 64 bit st_size */ #ifdef stat @@ -338,6 +384,9 @@ int mingw_raise(int sig); * ANSI emulation wrappers */ +int winansi_isatty(int fd); +#define isatty winansi_isatty + void winansi_init(void); HANDLE winansi_get_osfhandle(int fd); @@ -345,8 +394,15 @@ HANDLE winansi_get_osfhandle(int fd); * git specific compatibility */ -#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') -#define is_dir_sep(c) ((c) == '/' || (c) == '\\') +#define has_dos_drive_prefix(path) \ + (isalpha(*(path)) && (path)[1] == ':' ? 2 : 0) +int mingw_skip_dos_drive_prefix(char **path); +#define skip_dos_drive_prefix mingw_skip_dos_drive_prefix +static inline int mingw_is_dir_sep(int c) +{ + return c == '/' || c == '\\'; +} +#define is_dir_sep mingw_is_dir_sep static inline char *mingw_find_last_dir_sep(const char *path) { char *ret = NULL; @@ -355,18 +411,22 @@ static inline char *mingw_find_last_dir_sep(const char *path) ret = (char *)path; return ret; } +static inline void convert_slashes(char *path) +{ + for (; *path; path++) + if (*path == '\\') + *path = '/'; +} #define find_last_dir_sep mingw_find_last_dir_sep int mingw_offset_1st_component(const char *path); #define offset_1st_component mingw_offset_1st_component #define PATH_SEP ';' +#if !defined(__MINGW64_VERSION_MAJOR) && (!defined(_MSC_VER) || _MSC_VER < 1800) #define PRIuMAX "I64u" #define PRId64 "I64d" - -void mingw_open_html(const char *path); -#define open_html mingw_open_html - -void mingw_mark_as_git_dir(const char *dir); -#define mark_as_git_dir mingw_mark_as_git_dir +#else +#include <inttypes.h> +#endif /** * Converts UTF-8 encoded string to UTF-16LE. @@ -483,10 +543,10 @@ extern CRITICAL_SECTION pinfo_cs; * A replacement of main() that adds win32 specific initialization. */ -void mingw_startup(); -#define main(c,v) dummy_decl_mingw_main(); \ +void mingw_startup(void); +#define main(c,v) dummy_decl_mingw_main(void); \ static int mingw_main(c,v); \ -int main(int argc, char **argv) \ +int main(int argc, const char **argv) \ { \ mingw_startup(); \ return mingw_main(__argc, (void *)__argv); \ diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h index f216a2a7d3..b833ff9225 100644 --- a/compat/nedmalloc/malloc.c.h +++ b/compat/nedmalloc/malloc.c.h @@ -720,6 +720,9 @@ struct mallinfo { inlining are defined as macros, so these aren't used for them. */ +#ifdef __MINGW64_VERSION_MAJOR +#undef FORCEINLINE +#endif #ifndef FORCEINLINE #if defined(__GNUC__) #define FORCEINLINE __inline __attribute__ ((always_inline)) @@ -1382,6 +1385,7 @@ LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value); /*** Atomic operations ***/ #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100 + #undef _ReadWriteBarrier #define _ReadWriteBarrier() __sync_synchronize() #else static __inline__ __attribute__((always_inline)) long __sync_lock_test_and_set(volatile long * const Target, const long Value) @@ -1798,9 +1802,10 @@ struct win32_mlock_t volatile long threadid; }; +static inline int return_0(int i) { return 0; } #define MLOCK_T struct win32_mlock_t #define CURRENT_THREAD win32_getcurrentthreadid() -#define INITIAL_LOCK(sl) (memset(sl, 0, sizeof(MLOCK_T)), 0) +#define INITIAL_LOCK(sl) (memset(sl, 0, sizeof(MLOCK_T)), return_0(0)) #define ACQUIRE_LOCK(sl) win32_acquire_lock(sl) #define RELEASE_LOCK(sl) win32_release_lock(sl) #define TRY_LOCK(sl) win32_try_lock(sl) diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c index 609ebba125..1cc31c3502 100644 --- a/compat/nedmalloc/nedmalloc.c +++ b/compat/nedmalloc/nedmalloc.c @@ -938,32 +938,16 @@ void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void ** void **ret; threadcache *tc; int mymspace; - size_t i, *adjustedsizes=(size_t *) alloca(elems*sizeof(size_t)); - if(!adjustedsizes) return 0; - for(i=0; i<elems; i++) - adjustedsizes[i]=sizes[i]<sizeof(threadcacheblk) ? sizeof(threadcacheblk) : sizes[i]; + size_t i, *adjustedsizes=(size_t *) alloca(elems*sizeof(size_t)); + if(!adjustedsizes) return 0; + for(i=0; i<elems; i++) + adjustedsizes[i]=sizes[i]<sizeof(threadcacheblk) ? sizeof(threadcacheblk) : sizes[i]; GetThreadCache(&p, &tc, &mymspace, 0); GETMSPACE(m, p, tc, mymspace, 0, ret=mspace_independent_comalloc(m, elems, adjustedsizes, chunks)); return ret; } -#ifdef OVERRIDE_STRDUP -/* - * This implementation is purely there to override the libc version, to - * avoid a crash due to allocation and free on different 'heaps'. - */ -char *strdup(const char *s1) -{ - char *s2 = 0; - if (s1) { - s2 = malloc(strlen(s1) + 1); - strcpy(s2, s1); - } - return s2; -} -#endif - #if defined(__cplusplus) } #endif diff --git a/compat/poll/poll.c b/compat/poll/poll.c index a9b41d89f4..b10adc780f 100644 --- a/compat/poll/poll.c +++ b/compat/poll/poll.c @@ -76,7 +76,7 @@ #ifdef WIN32_NATIVE -#define IsConsoleHandle(h) (((long) (h) & 3) == 3) +#define IsConsoleHandle(h) (((long) (intptr_t) (h) & 3) == 3) static BOOL IsSocketHandle (HANDLE h) @@ -446,7 +446,7 @@ poll (struct pollfd *pfd, nfds_t nfd, int timeout) static HANDLE hEvent; WSANETWORKEVENTS ev; HANDLE h, handle_array[FD_SETSIZE + 2]; - DWORD ret, wait_timeout, nhandles; + DWORD ret, wait_timeout, nhandles, start = 0, elapsed, orig_timeout = 0; fd_set rfds, wfds, xfds; BOOL poll_again; MSG msg; @@ -459,6 +459,12 @@ poll (struct pollfd *pfd, nfds_t nfd, int timeout) return -1; } + if (timeout != INFTIM) + { + orig_timeout = timeout; + start = GetTickCount(); + } + if (!hEvent) hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); @@ -603,7 +609,13 @@ restart: rc++; } - if (!rc && timeout == INFTIM) + if (!rc && orig_timeout && timeout != INFTIM) + { + elapsed = GetTickCount() - start; + timeout = elapsed >= orig_timeout ? 0 : orig_timeout - elapsed; + } + + if (!rc && timeout) { SleepEx (1, TRUE); goto restart; diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c index 95fe849e42..4293b53b17 100644 --- a/compat/precompose_utf8.c +++ b/compat/precompose_utf8.c @@ -36,24 +36,27 @@ static size_t has_non_ascii(const char *s, size_t maxlen, size_t *strlen_c) } -void probe_utf8_pathname_composition(char *path, int len) +void probe_utf8_pathname_composition(void) { + struct strbuf path = STRBUF_INIT; static const char *auml_nfc = "\xc3\xa4"; static const char *auml_nfd = "\x61\xcc\x88"; int output_fd; if (precomposed_unicode != -1) return; /* We found it defined in the global config, respect it */ - strcpy(path + len, auml_nfc); - output_fd = open(path, O_CREAT|O_EXCL|O_RDWR, 0600); + git_path_buf(&path, "%s", auml_nfc); + output_fd = open(path.buf, O_CREAT|O_EXCL|O_RDWR, 0600); if (output_fd >= 0) { close(output_fd); - strcpy(path + len, auml_nfd); - precomposed_unicode = access(path, R_OK) ? 0 : 1; - git_config_set("core.precomposeunicode", precomposed_unicode ? "true" : "false"); - strcpy(path + len, auml_nfc); - if (unlink(path)) - die_errno(_("failed to unlink '%s'"), path); + git_path_buf(&path, "%s", auml_nfd); + precomposed_unicode = access(path.buf, R_OK) ? 0 : 1; + git_config_set("core.precomposeunicode", + precomposed_unicode ? "true" : "false"); + git_path_buf(&path, "%s", auml_nfc); + if (unlink(path.buf)) + die_errno(_("failed to unlink '%s'"), path.buf); } + strbuf_release(&path); } @@ -139,13 +142,12 @@ struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir) size_t inleft = namelenz; char *outpos = &prec_dir->dirent_nfc->d_name[0]; size_t outsz = prec_dir->dirent_nfc->max_name_len; - size_t cnt; errno = 0; - cnt = iconv(prec_dir->ic_precompose, &cp, &inleft, &outpos, &outsz); + iconv(prec_dir->ic_precompose, &cp, &inleft, &outpos, &outsz); if (errno || inleft) { /* * iconv() failed and errno could be E2BIG, EILSEQ, EINVAL, EBADF - * MacOS X avoids illegal byte sequemces. + * MacOS X avoids illegal byte sequences. * If they occur on a mounted drive (e.g. NFS) it is not worth to * die() for that, but rather let the user see the original name */ diff --git a/compat/precompose_utf8.h b/compat/precompose_utf8.h index 3b73585fc5..a94e7c4342 100644 --- a/compat/precompose_utf8.h +++ b/compat/precompose_utf8.h @@ -27,7 +27,7 @@ typedef struct { } PREC_DIR; void precompose_argv(int argc, const char **argv); -void probe_utf8_pathname_composition(char *, int); +void probe_utf8_pathname_composition(void); PREC_DIR *precompose_utf8_opendir(const char *dirname); struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *dirp); diff --git a/compat/qsort.c b/compat/qsort.c index 9574d537bd..7d071afb70 100644 --- a/compat/qsort.c +++ b/compat/qsort.c @@ -47,7 +47,7 @@ static void msort_with_tmp(void *b, size_t n, size_t s, void git_qsort(void *b, size_t n, size_t s, int (*cmp)(const void *, const void *)) { - const size_t size = n * s; + const size_t size = st_mult(n, s); char buf[1024]; if (size < sizeof(buf)) { diff --git a/compat/qsort_s.c b/compat/qsort_s.c new file mode 100644 index 0000000000..52d1f0a73d --- /dev/null +++ b/compat/qsort_s.c @@ -0,0 +1,69 @@ +#include "../git-compat-util.h" + +/* + * A merge sort implementation, simplified from the qsort implementation + * by Mike Haertel, which is a part of the GNU C Library. + * Added context pointer, safety checks and return value. + */ + +static void msort_with_tmp(void *b, size_t n, size_t s, + int (*cmp)(const void *, const void *, void *), + char *t, void *ctx) +{ + char *tmp; + char *b1, *b2; + size_t n1, n2; + + if (n <= 1) + return; + + n1 = n / 2; + n2 = n - n1; + b1 = b; + b2 = (char *)b + (n1 * s); + + msort_with_tmp(b1, n1, s, cmp, t, ctx); + msort_with_tmp(b2, n2, s, cmp, t, ctx); + + tmp = t; + + while (n1 > 0 && n2 > 0) { + if (cmp(b1, b2, ctx) <= 0) { + memcpy(tmp, b1, s); + tmp += s; + b1 += s; + --n1; + } else { + memcpy(tmp, b2, s); + tmp += s; + b2 += s; + --n2; + } + } + if (n1 > 0) + memcpy(tmp, b1, n1 * s); + memcpy(b, t, (n - n2) * s); +} + +int git_qsort_s(void *b, size_t n, size_t s, + int (*cmp)(const void *, const void *, void *), void *ctx) +{ + const size_t size = st_mult(n, s); + char buf[1024]; + + if (!n) + return 0; + if (!b || !cmp) + return -1; + + if (size < sizeof(buf)) { + /* The temporary array fits on the small on-stack buffer. */ + msort_with_tmp(b, n, s, cmp, buf, ctx); + } else { + /* It's somewhat large, so malloc it. */ + char *tmp = xmalloc(size); + msort_with_tmp(b, n, s, cmp, tmp, ctx); + free(tmp); + } + return 0; +} diff --git a/compat/regex/regcomp.c b/compat/regex/regcomp.c index 06f3088708..d8bde06f1a 100644 --- a/compat/regex/regcomp.c +++ b/compat/regex/regcomp.c @@ -2577,7 +2577,7 @@ parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa, old_tree = NULL; if (elem->token.type == SUBEXP) - postorder (elem, mark_opt_subexp, (void *) (long) elem->token.opr.idx); + postorder (elem, mark_opt_subexp, (void *) (intptr_t) elem->token.opr.idx); tree = create_tree (dfa, elem, NULL, (end == -1 ? OP_DUP_ASTERISK : OP_ALT)); if (BE (tree == NULL, 0)) @@ -3806,7 +3806,7 @@ create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node) { - int idx = (int) (long) extra; + int idx = (int) (intptr_t) extra; if (node->token.type == SUBEXP && node->token.opr.idx == idx) node->token.opt_subexp = 1; diff --git a/compat/regex/regex.c b/compat/regex/regex.c index 6aaae00327..5cb23e5d59 100644 --- a/compat/regex/regex.c +++ b/compat/regex/regex.c @@ -60,6 +60,7 @@ GNU regex allows. Include it before <regex.h>, which correctly #undefs RE_DUP_MAX and sets it to the right value. */ #include <limits.h> +#include <stdint.h> #ifdef GAWK #undef alloca diff --git a/compat/setenv.c b/compat/setenv.c index fc1439a643..7849f258d2 100644 --- a/compat/setenv.c +++ b/compat/setenv.c @@ -18,7 +18,7 @@ int gitsetenv(const char *name, const char *value, int replace) namelen = strlen(name); valuelen = strlen(value); - envstr = malloc((namelen + valuelen + 2)); + envstr = malloc(st_add3(namelen, valuelen, 2)); if (!envstr) { errno = ENOMEM; return -1; diff --git a/compat/sha1-chunked.c b/compat/sha1-chunked.c new file mode 100644 index 0000000000..6adfcfd540 --- /dev/null +++ b/compat/sha1-chunked.c @@ -0,0 +1,19 @@ +#include "cache.h" + +int git_SHA1_Update_Chunked(platform_SHA_CTX *c, const void *data, size_t len) +{ + size_t nr; + size_t total = 0; + const char *cdata = (const char*)data; + + while (len) { + nr = len; + if (nr > SHA1_MAX_BLOCK_SIZE) + nr = SHA1_MAX_BLOCK_SIZE; + platform_SHA1_Update(c, cdata, nr); + total += nr; + cdata += nr; + len -= nr; + } + return total; +} diff --git a/compat/sha1-chunked.h b/compat/sha1-chunked.h new file mode 100644 index 0000000000..7b2df28eec --- /dev/null +++ b/compat/sha1-chunked.h @@ -0,0 +1,2 @@ + +int git_SHA1_Update_Chunked(platform_SHA_CTX *c, const void *data, size_t len); diff --git a/compat/snprintf.c b/compat/snprintf.c index 42ea1ac110..0b11688537 100644 --- a/compat/snprintf.c +++ b/compat/snprintf.c @@ -9,7 +9,7 @@ * always have room for a trailing NUL byte. */ #ifndef SNPRINTF_SIZE_CORR -#if defined(WIN32) && (!defined(__GNUC__) || __GNUC__ < 4) +#if defined(WIN32) && (!defined(__GNUC__) || __GNUC__ < 4) && (!defined(_MSC_VER) || _MSC_VER < 1900) #define SNPRINTF_SIZE_CORR 1 #else #define SNPRINTF_SIZE_CORR 0 diff --git a/compat/strdup.c b/compat/strdup.c new file mode 100644 index 0000000000..f3fb978eb3 --- /dev/null +++ b/compat/strdup.c @@ -0,0 +1,11 @@ +#include "../git-compat-util.h" + +char *gitstrdup(const char *s1) +{ + size_t len = strlen(s1) + 1; + char *s2 = malloc(len); + + if (s2) + memcpy(s2, s1, len); + return s2; +} diff --git a/compat/terminal.c b/compat/terminal.c index 313897d581..fa13ee672d 100644 --- a/compat/terminal.c +++ b/compat/terminal.c @@ -122,7 +122,7 @@ char *git_terminal_prompt(const char *prompt, int echo) fputs(prompt, output_fh); fflush(output_fh); - r = strbuf_getline(&buf, input_fh, '\n'); + r = strbuf_getline_lf(&buf, input_fh); if (!echo) { putc('\n', output_fh); fflush(output_fh); diff --git a/compat/vcbuild/include/unistd.h b/compat/vcbuild/include/unistd.h index c65c2cd566..3a959d124c 100644 --- a/compat/vcbuild/include/unistd.h +++ b/compat/vcbuild/include/unistd.h @@ -45,11 +45,15 @@ typedef unsigned long long uintmax_t; typedef int64_t off64_t; +#if !defined(_MSC_VER) || _MSC_VER < 1600 #define INTMAX_MIN _I64_MIN #define INTMAX_MAX _I64_MAX #define UINTMAX_MAX _UI64_MAX #define UINT32_MAX 0xffffffff /* 4294967295U */ +#else +#include <stdint.h> +#endif #define STDIN_FILENO 0 #define STDOUT_FILENO 1 diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h index 8ad187344f..1c164088fb 100644 --- a/compat/win32/pthread.h +++ b/compat/win32/pthread.h @@ -18,7 +18,10 @@ */ #define pthread_mutex_t CRITICAL_SECTION -#define pthread_mutex_init(a,b) (InitializeCriticalSection((a)), 0) +static inline int return_0(int i) { + return 0; +} +#define pthread_mutex_init(a,b) return_0((InitializeCriticalSection((a)), 0)) #define pthread_mutex_destroy(a) DeleteCriticalSection((a)) #define pthread_mutex_lock EnterCriticalSection #define pthread_mutex_unlock LeaveCriticalSection @@ -75,9 +78,9 @@ extern int win32_pthread_join(pthread_t *thread, void **value_ptr); #define pthread_equal(t1, t2) ((t1).tid == (t2).tid) extern pthread_t pthread_self(void); -static inline int pthread_exit(void *ret) +static inline void NORETURN pthread_exit(void *ret) { - ExitThread((DWORD)ret); + ExitThread((DWORD)(intptr_t)ret); } typedef DWORD pthread_key_t; @@ -101,4 +104,11 @@ static inline void *pthread_getspecific(pthread_key_t key) return TlsGetValue(key); } +#ifndef __MINGW64_VERSION_MAJOR +static inline int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) +{ + return 0; +} +#endif + #endif /* PTHREAD_H */ diff --git a/compat/win32/syslog.c b/compat/win32/syslog.c index d015e436d5..6c7c9b6053 100644 --- a/compat/win32/syslog.c +++ b/compat/win32/syslog.c @@ -28,13 +28,13 @@ void syslog(int priority, const char *fmt, ...) va_end(ap); if (str_len < 0) { - warning("vsnprintf failed: '%s'", strerror(errno)); + warning_errno("vsnprintf failed"); return; } - str = malloc(str_len + 1); + str = malloc(st_add(str_len, 1)); if (!str) { - warning("malloc failed: '%s'", strerror(errno)); + warning_errno("malloc failed"); return; } @@ -43,9 +43,9 @@ void syslog(int priority, const char *fmt, ...) va_end(ap); while ((pos = strstr(str, "%1")) != NULL) { - str = realloc(str, ++str_len + 1); + str = realloc(str, st_add(++str_len, 1)); if (!str) { - warning("realloc failed: '%s'", strerror(errno)); + warning_errno("realloc failed"); return; } memmove(pos + 2, pos + 1, strlen(pos)); diff --git a/compat/win32mmap.c b/compat/win32mmap.c index 80a8c9af4f..519d51f2b6 100644 --- a/compat/win32mmap.c +++ b/compat/win32mmap.c @@ -2,37 +2,42 @@ void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) { - HANDLE hmap; + HANDLE osfhandle, hmap; void *temp; - off_t len; - struct stat st; + LARGE_INTEGER len; uint64_t o = offset; uint32_t l = o & 0xFFFFFFFF; uint32_t h = (o >> 32) & 0xFFFFFFFF; - if (!fstat(fd, &st)) - len = st.st_size; - else + osfhandle = (HANDLE)_get_osfhandle(fd); + if (!GetFileSizeEx(osfhandle, &len)) die("mmap: could not determine filesize"); - if ((length + offset) > len) - length = xsize_t(len - offset); + if ((length + offset) > len.QuadPart) + length = xsize_t(len.QuadPart - offset); if (!(flags & MAP_PRIVATE)) die("Invalid usage of mmap when built with USE_WIN32_MMAP"); - hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), NULL, - PAGE_WRITECOPY, 0, 0, NULL); + hmap = CreateFileMapping(osfhandle, NULL, + prot == PROT_READ ? PAGE_READONLY : PAGE_WRITECOPY, 0, 0, NULL); - if (!hmap) + if (!hmap) { + errno = EINVAL; return MAP_FAILED; + } - temp = MapViewOfFileEx(hmap, FILE_MAP_COPY, h, l, length, start); + temp = MapViewOfFileEx(hmap, prot == PROT_READ ? + FILE_MAP_READ : FILE_MAP_COPY, h, l, length, start); if (!CloseHandle(hmap)) warning("unable to close file mapping handle"); - return temp ? temp : MAP_FAILED; + if (temp) + return temp; + + errno = GetLastError() == ERROR_COMMITMENT_LIMIT ? EFBIG : EINVAL; + return MAP_FAILED; } int git_munmap(void *start, size_t length) diff --git a/compat/winansi.c b/compat/winansi.c index efc5bb3a4b..a11a0f16d2 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -6,6 +6,12 @@ #include "../git-compat-util.h" #include <wingdi.h> #include <winreg.h> +#include "win32.h" + +static int fd_is_interactive[3] = { 0, 0, 0 }; +#define FD_CONSOLE 0x1 +#define FD_SWAPPED 0x2 +#define FD_MSYS 0x4 /* ANSI codes used by git: m, K @@ -23,6 +29,7 @@ static HANDLE hthread, hread, hwrite; static HANDLE hconsole1, hconsole2; #ifdef __MINGW32__ +#if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 5 typedef struct _CONSOLE_FONT_INFOEX { ULONG cbSize; DWORD nFont; @@ -32,6 +39,7 @@ typedef struct _CONSOLE_FONT_INFOEX { WCHAR FaceName[LF_FACESIZE]; } CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX; #endif +#endif typedef BOOL (WINAPI *PGETCURRENTCONSOLEFONTEX)(HANDLE, BOOL, PCONSOLE_FONT_INFOEX); @@ -79,6 +87,7 @@ static void warn_if_raster_font(void) static int is_console(int fd) { CONSOLE_SCREEN_BUFFER_INFO sbi; + DWORD mode; HANDLE hcon; static int initialized = 0; @@ -93,9 +102,22 @@ static int is_console(int fd) return 0; /* check if its a handle to a console output screen buffer */ - if (!GetConsoleScreenBufferInfo(hcon, &sbi)) + if (!fd) { + if (!GetConsoleMode(hcon, &mode)) + return 0; + /* + * This code path is only reached if there is no console + * attached to stdout/stderr, i.e. we will not need to output + * any text to any console, therefore we might just as well + * use black as foreground color. + */ + sbi.wAttributes = 0; + } else if (!GetConsoleScreenBufferInfo(hcon, &sbi)) return 0; + if (fd >= 0 && fd <= 2) + fd_is_interactive[fd] |= FD_CONSOLE; + /* initialize attributes */ if (!initialized) { console = hcon; @@ -118,6 +140,11 @@ static void write_console(unsigned char *str, size_t len) /* convert utf-8 to utf-16 */ int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len); + if (wlen < 0) { + wchar_t *err = L"[invalid]"; + WriteConsoleW(console, err, wcslen(err), &dummy, NULL); + return; + } /* write directly to console */ WriteConsoleW(console, wbuf, wlen, &dummy, NULL); @@ -452,79 +479,109 @@ static HANDLE duplicate_handle(HANDLE hnd) HANDLE hresult, hproc = GetCurrentProcess(); if (!DuplicateHandle(hproc, hnd, hproc, &hresult, 0, TRUE, DUPLICATE_SAME_ACCESS)) - die_lasterr("DuplicateHandle(%li) failed", (long) hnd); + die_lasterr("DuplicateHandle(%li) failed", + (long) (intptr_t) hnd); return hresult; } +static HANDLE swap_osfhnd(int fd, HANDLE new_handle) +{ + /* + * Create a copy of the original handle associated with fd + * because the original will get closed when we dup2(). + */ + HANDLE handle = (HANDLE)_get_osfhandle(fd); + HANDLE duplicate = duplicate_handle(handle); + + /* Create a temp fd associated with the already open "new_handle". */ + int new_fd = _open_osfhandle((intptr_t)new_handle, O_BINARY); + + assert((fd == 1) || (fd == 2)); + + /* + * Use stock dup2() to re-bind fd to the new handle. Note that + * this will implicitly close(1) and close both fd=1 and the + * originally associated handle. It will open a new fd=1 and + * call DuplicateHandle() on the handle associated with new_fd. + * It is because of this implicit close() that we created the + * copy of the original. + * + * Note that we need to update the cached console handle to the + * duplicated one because the dup2() call will implicitly close + * the original one. + * + * Note that dup2() when given target := {0,1,2} will also + * call SetStdHandle(), so we don't need to worry about that. + */ + if (console == handle) + console = duplicate; + dup2(new_fd, fd); + + /* Close the temp fd. This explicitly closes "new_handle" + * (because it has been associated with it). + */ + close(new_fd); + + if (fd == 2) + setvbuf(stderr, NULL, _IONBF, BUFSIZ); + fd_is_interactive[fd] |= FD_SWAPPED; + + return duplicate; +} -/* - * Make MSVCRT's internal file descriptor control structure accessible - * so that we can tweak OS handles and flags directly (we need MSVCRT - * to treat our pipe handle as if it were a console). - * - * We assume that the ioinfo structure (exposed by MSVCRT.dll via - * __pioinfo) starts with the OS handle and the flags. The exact size - * varies between MSVCRT versions, so we try different sizes until - * toggling the FDEV bit of _pioinfo(1)->osflags is reflected in - * isatty(1). - */ -typedef struct { - HANDLE osfhnd; - char osflags; -} ioinfo; - -extern __declspec(dllimport) ioinfo *__pioinfo[]; +#ifdef DETECT_MSYS_TTY -static size_t sizeof_ioinfo = 0; +#include <winternl.h> +#include <ntstatus.h> -#define IOINFO_L2E 5 -#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E) +static void detect_msys_tty(int fd) +{ + ULONG result; + BYTE buffer[1024]; + POBJECT_NAME_INFORMATION nameinfo = (POBJECT_NAME_INFORMATION) buffer; + PWSTR name; + + /* check if fd is a pipe */ + HANDLE h = (HANDLE) _get_osfhandle(fd); + if (GetFileType(h) != FILE_TYPE_PIPE) + return; -#define FDEV 0x40 + /* get pipe name */ + if (!NT_SUCCESS(NtQueryObject(h, ObjectNameInformation, + buffer, sizeof(buffer) - 2, &result))) + return; + name = nameinfo->Name.Buffer; + name[nameinfo->Name.Length / sizeof(*name)] = 0; + + /* + * Check if this could be a MSYS2 pty pipe ('msys-XXXX-ptyN-XX') + * or a cygwin pty pipe ('cygwin-XXXX-ptyN-XX') + */ + if ((!wcsstr(name, L"msys-") && !wcsstr(name, L"cygwin-")) || + !wcsstr(name, L"-pty")) + return; -static inline ioinfo* _pioinfo(int fd) -{ - return (ioinfo*)((char*)__pioinfo[fd >> IOINFO_L2E] + - (fd & (IOINFO_ARRAY_ELTS - 1)) * sizeof_ioinfo); + if (fd == 2) + setvbuf(stderr, NULL, _IONBF, BUFSIZ); + fd_is_interactive[fd] |= FD_MSYS; } -static int init_sizeof_ioinfo() -{ - int istty, wastty; - /* don't init twice */ - if (sizeof_ioinfo) - return sizeof_ioinfo >= 256; - - sizeof_ioinfo = sizeof(ioinfo); - wastty = isatty(1); - while (sizeof_ioinfo < 256) { - /* toggle FDEV flag, check isatty, then toggle back */ - _pioinfo(1)->osflags ^= FDEV; - istty = isatty(1); - _pioinfo(1)->osflags ^= FDEV; - /* return if we found the correct size */ - if (istty != wastty) - return 0; - sizeof_ioinfo += sizeof(void*); - } - error("Tweaking file descriptors doesn't work with this MSVCRT.dll"); - return 1; -} +#endif -static HANDLE swap_osfhnd(int fd, HANDLE new_handle) +/* + * Wrapper for isatty(). Most calls in the main git code + * call isatty(1 or 2) to see if the instance is interactive + * and should: be colored, show progress, paginate output. + * We lie and give results for what the descriptor WAS at + * startup (and ignore any pipe redirection we internally + * do). + */ +#undef isatty +int winansi_isatty(int fd) { - ioinfo *pioinfo; - HANDLE old_handle; - - /* init ioinfo size if we haven't done so */ - if (init_sizeof_ioinfo()) - return INVALID_HANDLE_VALUE; - - /* get ioinfo pointer and change the handles */ - pioinfo = _pioinfo(fd); - old_handle = pioinfo->osfhnd; - pioinfo->osfhnd = new_handle; - return old_handle; + if (fd >= 0 && fd <= 2) + return fd_is_interactive[fd] != 0; + return isatty(fd); } void winansi_init(void) @@ -535,11 +592,22 @@ void winansi_init(void) /* check if either stdout or stderr is a console output screen buffer */ con1 = is_console(1); con2 = is_console(2); - if (!con1 && !con2) + + /* Also compute console bit for fd 0 even though we don't need the result here. */ + is_console(0); + + if (!con1 && !con2) { +#ifdef DETECT_MSYS_TTY + /* check if stdin / stdout / stderr are MSYS2 pty pipes */ + detect_msys_tty(0); + detect_msys_tty(1); + detect_msys_tty(2); +#endif return; + } /* create a named pipe to communicate with the console thread */ - sprintf(name, "\\\\.\\pipe\\winansi%lu", GetCurrentProcessId()); + xsnprintf(name, sizeof(name), "\\\\.\\pipe\\winansi%lu", GetCurrentProcessId()); hwrite = CreateNamedPipe(name, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE | PIPE_WAIT, 1, BUFFER_SIZE, 0, 0, NULL); if (hwrite == INVALID_HANDLE_VALUE) @@ -571,9 +639,10 @@ void winansi_init(void) */ HANDLE winansi_get_osfhandle(int fd) { - HANDLE hnd = (HANDLE) _get_osfhandle(fd); - if ((fd == 1 || fd == 2) && isatty(fd) - && GetFileType(hnd) == FILE_TYPE_PIPE) - return (fd == 1) ? hconsole1 : hconsole2; - return hnd; + if (fd == 1 && (fd_is_interactive[1] & FD_SWAPPED)) + return hconsole1; + if (fd == 2 && (fd_is_interactive[2] & FD_SWAPPED)) + return hconsole2; + + return (HANDLE)_get_osfhandle(fd); } |