summaryrefslogtreecommitdiff
path: root/compat
diff options
context:
space:
mode:
Diffstat (limited to 'compat')
-rw-r--r--compat/apple-common-crypto.h20
-rw-r--r--compat/basename.c66
-rw-r--r--compat/bswap.h5
-rw-r--r--compat/hstrerror.c2
-rw-r--r--compat/inet_ntop.c6
-rw-r--r--compat/mingw.c286
-rw-r--r--compat/mingw.h88
-rw-r--r--compat/nedmalloc/malloc.c.h7
-rw-r--r--compat/nedmalloc/nedmalloc.c24
-rw-r--r--compat/poll/poll.c18
-rw-r--r--compat/precompose_utf8.c26
-rw-r--r--compat/precompose_utf8.h2
-rw-r--r--compat/qsort.c2
-rw-r--r--compat/qsort_s.c69
-rw-r--r--compat/regex/regcomp.c4
-rw-r--r--compat/regex/regex.c1
-rw-r--r--compat/setenv.c2
-rw-r--r--compat/sha1-chunked.c19
-rw-r--r--compat/sha1-chunked.h2
-rw-r--r--compat/snprintf.c2
-rw-r--r--compat/strdup.c11
-rw-r--r--compat/terminal.c2
-rw-r--r--compat/vcbuild/include/unistd.h4
-rw-r--r--compat/win32/pthread.h16
-rw-r--r--compat/win32/syslog.c10
-rw-r--r--compat/win32mmap.c31
-rw-r--r--compat/winansi.c207
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);
}