summaryrefslogtreecommitdiff
path: root/compat
diff options
context:
space:
mode:
Diffstat (limited to 'compat')
-rw-r--r--compat/cygwin.c143
-rw-r--r--compat/cygwin.h9
-rw-r--r--compat/fnmatch/fnmatch.c4
-rw-r--r--compat/memmem.c5
-rw-r--r--compat/mingw.c261
-rw-r--r--compat/mingw.h39
-rw-r--r--compat/regex/regex.c4
-rw-r--r--compat/win32.h34
-rw-r--r--compat/win32mmap.c53
-rw-r--r--compat/winansi.c18
10 files changed, 464 insertions, 106 deletions
diff --git a/compat/cygwin.c b/compat/cygwin.c
new file mode 100644
index 0000000000..b4a51b958c
--- /dev/null
+++ b/compat/cygwin.c
@@ -0,0 +1,143 @@
+#define WIN32_LEAN_AND_MEAN
+#include "../git-compat-util.h"
+#include "win32.h"
+#include "../cache.h" /* to read configuration */
+
+static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
+{
+ long long winTime = ((long long)ft->dwHighDateTime << 32) +
+ ft->dwLowDateTime;
+ winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
+ /* convert 100-nsecond interval to seconds and nanoseconds */
+ ts->tv_sec = (time_t)(winTime/10000000);
+ ts->tv_nsec = (long)(winTime - ts->tv_sec*10000000LL) * 100;
+}
+
+#define size_to_blocks(s) (((s)+511)/512)
+
+/* do_stat is a common implementation for cygwin_lstat and cygwin_stat.
+ *
+ * To simplify its logic, in the case of cygwin symlinks, this implementation
+ * falls back to the cygwin version of stat/lstat, which is provided as the
+ * last argument.
+ */
+static int do_stat(const char *file_name, struct stat *buf, stat_fn_t cygstat)
+{
+ WIN32_FILE_ATTRIBUTE_DATA fdata;
+
+ if (file_name[0] == '/')
+ return cygstat (file_name, buf);
+
+ if (!(errno = get_file_attr(file_name, &fdata))) {
+ /*
+ * If the system attribute is set and it is not a directory then
+ * it could be a symbol link created in the nowinsymlinks mode.
+ * Normally, Cygwin works in the winsymlinks mode, so this situation
+ * is very unlikely. For the sake of simplicity of our code, let's
+ * Cygwin to handle it.
+ */
+ if ((fdata.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) &&
+ !(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ return cygstat(file_name, buf);
+
+ /* fill out the stat structure */
+ buf->st_dev = buf->st_rdev = 0; /* not used by Git */
+ buf->st_ino = 0;
+ buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
+ buf->st_nlink = 1;
+ buf->st_uid = buf->st_gid = 0;
+#ifdef __CYGWIN_USE_BIG_TYPES__
+ buf->st_size = ((_off64_t)fdata.nFileSizeHigh << 32) +
+ fdata.nFileSizeLow;
+#else
+ buf->st_size = (off_t)fdata.nFileSizeLow;
+#endif
+ buf->st_blocks = size_to_blocks(buf->st_size);
+ filetime_to_timespec(&fdata.ftLastAccessTime, &buf->st_atim);
+ filetime_to_timespec(&fdata.ftLastWriteTime, &buf->st_mtim);
+ filetime_to_timespec(&fdata.ftCreationTime, &buf->st_ctim);
+ return 0;
+ } else if (errno == ENOENT) {
+ /*
+ * In the winsymlinks mode (which is the default), Cygwin
+ * emulates symbol links using Windows shortcut files. These
+ * files are formed by adding .lnk extension. So, if we have
+ * not found the specified file name, it could be that it is
+ * a symbol link. Let's Cygwin to deal with that.
+ */
+ return cygstat(file_name, buf);
+ }
+ return -1;
+}
+
+/* We provide our own lstat/stat functions, since the provided Cygwin versions
+ * of these functions are too slow. These stat functions are tailored for Git's
+ * usage, and therefore they are not meant to be complete and correct emulation
+ * of lstat/stat functionality.
+ */
+static int cygwin_lstat(const char *path, struct stat *buf)
+{
+ return do_stat(path, buf, lstat);
+}
+
+static int cygwin_stat(const char *path, struct stat *buf)
+{
+ return do_stat(path, buf, stat);
+}
+
+
+/*
+ * At start up, we are trying to determine whether Win32 API or cygwin stat
+ * functions should be used. The choice is determined by core.ignorecygwinfstricks.
+ * Reading this option is not always possible immediately as git_dir may
+ * not be set yet. So until it is set, use cygwin lstat/stat functions.
+ * However, if core.filemode is set, we must use the Cygwin posix
+ * stat/lstat as the Windows stat functions do not determine posix filemode.
+ *
+ * Note that git_cygwin_config() does NOT call git_default_config() and this
+ * is deliberate. Many commands read from config to establish initial
+ * values in variables and later tweak them from elsewhere (e.g. command line).
+ * init_stat() is called lazily on demand, typically much late in the program,
+ * and calling git_default_config() from here would break such variables.
+ */
+static int native_stat = 1;
+static int core_filemode;
+
+static int git_cygwin_config(const char *var, const char *value, void *cb)
+{
+ if (!strcmp(var, "core.ignorecygwinfstricks"))
+ native_stat = git_config_bool(var, value);
+ else if (!strcmp(var, "core.filemode"))
+ core_filemode = git_config_bool(var, value);
+ return 0;
+}
+
+static int init_stat(void)
+{
+ if (have_git_dir()) {
+ git_config(git_cygwin_config, NULL);
+ if (!core_filemode && native_stat) {
+ cygwin_stat_fn = cygwin_stat;
+ cygwin_lstat_fn = cygwin_lstat;
+ } else {
+ cygwin_stat_fn = stat;
+ cygwin_lstat_fn = lstat;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+static int cygwin_stat_stub(const char *file_name, struct stat *buf)
+{
+ return (init_stat() ? stat : *cygwin_stat_fn)(file_name, buf);
+}
+
+static int cygwin_lstat_stub(const char *file_name, struct stat *buf)
+{
+ return (init_stat() ? lstat : *cygwin_lstat_fn)(file_name, buf);
+}
+
+stat_fn_t cygwin_stat_fn = cygwin_stat_stub;
+stat_fn_t cygwin_lstat_fn = cygwin_lstat_stub;
+
diff --git a/compat/cygwin.h b/compat/cygwin.h
new file mode 100644
index 0000000000..a3229f5b4f
--- /dev/null
+++ b/compat/cygwin.h
@@ -0,0 +1,9 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+
+typedef int (*stat_fn_t)(const char*, struct stat*);
+extern stat_fn_t cygwin_stat_fn;
+extern stat_fn_t cygwin_lstat_fn;
+
+#define stat(path, buf) (*cygwin_stat_fn)(path, buf)
+#define lstat(path, buf) (*cygwin_lstat_fn)(path, buf)
diff --git a/compat/fnmatch/fnmatch.c b/compat/fnmatch/fnmatch.c
index 1f4ead5f98..14feac7fe1 100644
--- a/compat/fnmatch/fnmatch.c
+++ b/compat/fnmatch/fnmatch.c
@@ -39,7 +39,7 @@
# include <stdlib.h>
#endif
-/* For platform which support the ISO C amendement 1 functionality we
+/* For platforms which support the ISO C amendment 1 functionality we
support user defined character classes. */
#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
@@ -90,7 +90,7 @@
# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
/* The GNU C library provides support for user-defined character classes
- and the functions from ISO C amendement 1. */
+ and the functions from ISO C amendment 1. */
# ifdef CHARCLASS_NAME_MAX
# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
# else
diff --git a/compat/memmem.c b/compat/memmem.c
index cd0d877364..56bcb4277f 100644
--- a/compat/memmem.c
+++ b/compat/memmem.c
@@ -5,6 +5,8 @@ void *gitmemmem(const void *haystack, size_t haystack_len,
{
const char *begin = haystack;
const char *last_possible = begin + haystack_len - needle_len;
+ const char *tail = needle;
+ char point;
/*
* The first occurrence of the empty string is deemed to occur at
@@ -20,8 +22,9 @@ void *gitmemmem(const void *haystack, size_t haystack_len,
if (haystack_len < needle_len)
return NULL;
+ point = *tail++;
for (; begin <= last_possible; begin++) {
- if (!memcmp(begin, needle, needle_len))
+ if (*begin == point && !memcmp(begin + 1, tail, needle_len - 1))
return (void *)begin;
}
diff --git a/compat/mingw.c b/compat/mingw.c
index 45733f9e04..cdeda1d985 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1,8 +1,122 @@
#include "../git-compat-util.h"
+#include "win32.h"
#include "../strbuf.h"
unsigned int _CRT_fmode = _O_BINARY;
+static int err_win_to_posix(DWORD winerr)
+{
+ int error = ENOSYS;
+ switch(winerr) {
+ case ERROR_ACCESS_DENIED: error = EACCES; break;
+ case ERROR_ACCOUNT_DISABLED: error = EACCES; break;
+ case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break;
+ case ERROR_ALREADY_ASSIGNED: error = EBUSY; break;
+ case ERROR_ALREADY_EXISTS: error = EEXIST; break;
+ case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break;
+ case ERROR_BAD_COMMAND: error = EIO; break;
+ case ERROR_BAD_DEVICE: error = ENODEV; break;
+ case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break;
+ case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break;
+ case ERROR_BAD_FORMAT: error = ENOEXEC; break;
+ case ERROR_BAD_LENGTH: error = EINVAL; break;
+ case ERROR_BAD_PATHNAME: error = ENOENT; break;
+ case ERROR_BAD_PIPE: error = EPIPE; break;
+ case ERROR_BAD_UNIT: error = ENODEV; break;
+ case ERROR_BAD_USERNAME: error = EINVAL; break;
+ case ERROR_BROKEN_PIPE: error = EPIPE; break;
+ case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break;
+ case ERROR_BUSY: error = EBUSY; break;
+ case ERROR_BUSY_DRIVE: error = EBUSY; break;
+ case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break;
+ case ERROR_CANNOT_MAKE: error = EACCES; break;
+ case ERROR_CANTOPEN: error = EIO; break;
+ case ERROR_CANTREAD: error = EIO; break;
+ case ERROR_CANTWRITE: error = EIO; break;
+ case ERROR_CRC: error = EIO; break;
+ case ERROR_CURRENT_DIRECTORY: error = EACCES; break;
+ case ERROR_DEVICE_IN_USE: error = EBUSY; break;
+ case ERROR_DEV_NOT_EXIST: error = ENODEV; break;
+ case ERROR_DIRECTORY: error = EINVAL; break;
+ case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break;
+ case ERROR_DISK_CHANGE: error = EIO; break;
+ case ERROR_DISK_FULL: error = ENOSPC; break;
+ case ERROR_DRIVE_LOCKED: error = EBUSY; break;
+ case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break;
+ case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break;
+ case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break;
+ case ERROR_FILE_EXISTS: error = EEXIST; break;
+ case ERROR_FILE_INVALID: error = ENODEV; break;
+ case ERROR_FILE_NOT_FOUND: error = ENOENT; break;
+ case ERROR_GEN_FAILURE: error = EIO; break;
+ case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break;
+ case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break;
+ case ERROR_INVALID_ACCESS: error = EACCES; break;
+ case ERROR_INVALID_ADDRESS: error = EFAULT; break;
+ case ERROR_INVALID_BLOCK: error = EFAULT; break;
+ case ERROR_INVALID_DATA: error = EINVAL; break;
+ case ERROR_INVALID_DRIVE: error = ENODEV; break;
+ case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break;
+ case ERROR_INVALID_FLAGS: error = EINVAL; break;
+ case ERROR_INVALID_FUNCTION: error = ENOSYS; break;
+ case ERROR_INVALID_HANDLE: error = EBADF; break;
+ case ERROR_INVALID_LOGON_HOURS: error = EACCES; break;
+ case ERROR_INVALID_NAME: error = EINVAL; break;
+ case ERROR_INVALID_OWNER: error = EINVAL; break;
+ case ERROR_INVALID_PARAMETER: error = EINVAL; break;
+ case ERROR_INVALID_PASSWORD: error = EPERM; break;
+ case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break;
+ case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break;
+ case ERROR_INVALID_TARGET_HANDLE: error = EIO; break;
+ case ERROR_INVALID_WORKSTATION: error = EACCES; break;
+ case ERROR_IO_DEVICE: error = EIO; break;
+ case ERROR_IO_INCOMPLETE: error = EINTR; break;
+ case ERROR_LOCKED: error = EBUSY; break;
+ case ERROR_LOCK_VIOLATION: error = EACCES; break;
+ case ERROR_LOGON_FAILURE: error = EACCES; break;
+ case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break;
+ case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break;
+ case ERROR_MORE_DATA: error = EPIPE; break;
+ case ERROR_NEGATIVE_SEEK: error = ESPIPE; break;
+ case ERROR_NOACCESS: error = EFAULT; break;
+ case ERROR_NONE_MAPPED: error = EINVAL; break;
+ case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break;
+ case ERROR_NOT_READY: error = EAGAIN; break;
+ case ERROR_NOT_SAME_DEVICE: error = EXDEV; break;
+ case ERROR_NO_DATA: error = EPIPE; break;
+ case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break;
+ case ERROR_NO_PROC_SLOTS: error = EAGAIN; break;
+ case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break;
+ case ERROR_OPEN_FAILED: error = EIO; break;
+ case ERROR_OPEN_FILES: error = EBUSY; break;
+ case ERROR_OPERATION_ABORTED: error = EINTR; break;
+ case ERROR_OUTOFMEMORY: error = ENOMEM; break;
+ case ERROR_PASSWORD_EXPIRED: error = EACCES; break;
+ case ERROR_PATH_BUSY: error = EBUSY; break;
+ case ERROR_PATH_NOT_FOUND: error = ENOENT; break;
+ case ERROR_PIPE_BUSY: error = EBUSY; break;
+ case ERROR_PIPE_CONNECTED: error = EPIPE; break;
+ case ERROR_PIPE_LISTENING: error = EPIPE; break;
+ case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break;
+ case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break;
+ case ERROR_READ_FAULT: error = EIO; break;
+ case ERROR_SEEK: error = EIO; break;
+ case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break;
+ case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break;
+ case ERROR_SHARING_VIOLATION: error = EACCES; break;
+ case ERROR_STACK_OVERFLOW: error = ENOMEM; break;
+ case ERROR_SWAPERROR: error = ENOENT; break;
+ case ERROR_TOO_MANY_MODULES: error = EMFILE; break;
+ case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break;
+ case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break;
+ case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break;
+ case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break;
+ case ERROR_WRITE_FAULT: error = EIO; break;
+ case ERROR_WRITE_PROTECT: error = EROFS; break;
+ }
+ return error;
+}
+
#undef open
int mingw_open (const char *filename, int oflags, ...)
{
@@ -31,12 +145,6 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)
return (time_t)winTime;
}
-static inline size_t size_to_blocks(size_t s)
-{
- return (s+511)/512;
-}
-
-extern int _getdrive( void );
/* 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.
@@ -45,46 +153,20 @@ static int do_lstat(const char *file_name, struct stat *buf)
{
WIN32_FILE_ATTRIBUTE_DATA fdata;
- if (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) {
- int fMode = S_IREAD;
- if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- fMode |= S_IFDIR;
- else
- fMode |= S_IFREG;
- if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
- fMode |= S_IWRITE;
-
+ if (!(errno = get_file_attr(file_name, &fdata))) {
buf->st_ino = 0;
buf->st_gid = 0;
buf->st_uid = 0;
- buf->st_mode = fMode;
- buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
- buf->st_blocks = size_to_blocks(buf->st_size);
- buf->st_dev = _getdrive() - 1;
+ buf->st_nlink = 1;
+ buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
+ buf->st_size = fdata.nFileSizeLow |
+ (((off_t)fdata.nFileSizeHigh)<<32);
+ buf->st_dev = buf->st_rdev = 0; /* not used by Git */
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
- errno = 0;
return 0;
}
-
- switch (GetLastError()) {
- case ERROR_ACCESS_DENIED:
- case ERROR_SHARING_VIOLATION:
- case ERROR_LOCK_VIOLATION:
- case ERROR_SHARING_BUFFER_EXCEEDED:
- errno = EACCES;
- break;
- case ERROR_BUFFER_OVERFLOW:
- errno = ENAMETOOLONG;
- break;
- case ERROR_NOT_ENOUGH_MEMORY:
- errno = ENOMEM;
- break;
- default:
- errno = ENOENT;
- break;
- }
return -1;
}
@@ -94,7 +176,7 @@ static int do_lstat(const char *file_name, struct stat *buf)
* complete. Note that Git stat()s are redirected to mingw_lstat()
* too, since Windows doesn't really handle symlinks that well.
*/
-int mingw_lstat(const char *file_name, struct mingw_stat *buf)
+int mingw_lstat(const char *file_name, struct stat *buf)
{
int namelen;
static char alt_name[PATH_MAX];
@@ -122,8 +204,7 @@ int mingw_lstat(const char *file_name, struct mingw_stat *buf)
}
#undef fstat
-#undef stat
-int mingw_fstat(int fd, struct mingw_stat *buf)
+int mingw_fstat(int fd, struct stat *buf)
{
HANDLE fh = (HANDLE)_get_osfhandle(fd);
BY_HANDLE_FILE_INFORMATION fdata;
@@ -133,39 +214,18 @@ int mingw_fstat(int fd, struct mingw_stat *buf)
return -1;
}
/* direct non-file handles to MS's fstat() */
- if (GetFileType(fh) != FILE_TYPE_DISK) {
- struct stat st;
- if (fstat(fd, &st))
- return -1;
- buf->st_ino = st.st_ino;
- buf->st_gid = st.st_gid;
- buf->st_uid = st.st_uid;
- buf->st_mode = st.st_mode;
- buf->st_size = st.st_size;
- buf->st_blocks = size_to_blocks(buf->st_size);
- buf->st_dev = st.st_dev;
- buf->st_atime = st.st_atime;
- buf->st_mtime = st.st_mtime;
- buf->st_ctime = st.st_ctime;
- return 0;
- }
+ if (GetFileType(fh) != FILE_TYPE_DISK)
+ return _fstati64(fd, buf);
if (GetFileInformationByHandle(fh, &fdata)) {
- int fMode = S_IREAD;
- if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- fMode |= S_IFDIR;
- else
- fMode |= S_IFREG;
- if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
- fMode |= S_IWRITE;
-
buf->st_ino = 0;
buf->st_gid = 0;
buf->st_uid = 0;
- buf->st_mode = fMode;
- buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
- buf->st_blocks = size_to_blocks(buf->st_size);
- buf->st_dev = _getdrive() - 1;
+ buf->st_nlink = 1;
+ buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
+ buf->st_size = fdata.nFileSizeLow |
+ (((off_t)fdata.nFileSizeHigh)<<32);
+ buf->st_dev = buf->st_rdev = 0; /* not used by Git */
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
@@ -283,8 +343,13 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout)
{
int i, pending;
- if (timeout != -1)
+ if (timeout >= 0) {
+ if (nfds == 0) {
+ Sleep(timeout);
+ return 0;
+ }
return errno = EINVAL, error("poll timeout not supported");
+ }
/* When there is only one fd to wait for, then we pretend that
* input is available and let the actual wait happen when the
@@ -331,7 +396,7 @@ repeat:
* its own input data to become available. But since
* the process (pack-objects) is itself CPU intensive,
* it will happily pick up the time slice that we are
- * relinguishing here.
+ * relinquishing here.
*/
Sleep(0);
goto repeat;
@@ -392,7 +457,7 @@ static const char *quote_arg(const char *arg)
const char *p = arg;
if (!*p) force_quotes = 1;
while (*p) {
- if (isspace(*p) || *p == '*' || *p == '?' || *p == '{')
+ if (isspace(*p) || *p == '*' || *p == '?' || *p == '{' || *p == '\'')
force_quotes = 1;
else if (*p == '"')
n++;
@@ -497,7 +562,7 @@ static char **get_path_split(void)
if (!n)
return NULL;
- path = xmalloc((n+1)*sizeof(char*));
+ path = xmalloc((n+1)*sizeof(char *));
p = envpath;
i = 0;
do {
@@ -586,12 +651,16 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
* would normally create a console window. But
* since we'll be redirecting std streams, we do
* not need the console.
+ * It is necessary to use DETACHED_PROCESS
+ * instead of CREATE_NO_WINDOW to make ssh
+ * recognize that it has no console.
*/
- flags = CREATE_NO_WINDOW;
+ flags = DETACHED_PROCESS;
} else {
/* There is already a console. If we specified
- * CREATE_NO_WINDOW here, too, Windows would
+ * DETACHED_PROCESS here, too, Windows would
* disassociate the child from the console.
+ * The same is true for CREATE_NO_WINDOW.
* Go figure!
*/
flags = 0;
@@ -865,7 +934,9 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
#undef rename
int mingw_rename(const char *pold, const char *pnew)
{
- DWORD attrs;
+ DWORD attrs, gle;
+ int tries = 0;
+ static const int delay[] = { 0, 1, 10, 20, 40 };
/*
* Try native rename() first to get errno right.
@@ -875,10 +946,12 @@ int mingw_rename(const char *pold, const char *pnew)
return 0;
if (errno != EEXIST)
return -1;
+repeat:
if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
return 0;
/* TODO: translate more errors */
- if (GetLastError() == ERROR_ACCESS_DENIED &&
+ gle = GetLastError();
+ if (gle == ERROR_ACCESS_DENIED &&
(attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
errno = EISDIR;
@@ -888,10 +961,23 @@ int mingw_rename(const char *pold, const char *pnew)
SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
return 0;
+ gle = GetLastError();
/* revert file attributes on failure */
SetFileAttributes(pnew, attrs);
}
}
+ if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
+ /*
+ * We assume that some other process had the source or
+ * destination file open at the wrong moment and retry.
+ * In order to give the other process a higher chance to
+ * complete its operation, we give up our time slice now.
+ * If we have to retry again, we do sleep a bit.
+ */
+ Sleep(delay[tries]);
+ tries++;
+ goto repeat;
+ }
errno = EACCES;
return -1;
}
@@ -1049,3 +1135,24 @@ void mingw_open_html(const char *unixpath)
printf("Launching default browser to display HTML ...\n");
ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0);
}
+
+int link(const char *oldpath, const char *newpath)
+{
+ typedef BOOL WINAPI (*T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
+ static T create_hard_link = NULL;
+ if (!create_hard_link) {
+ create_hard_link = (T) GetProcAddress(
+ GetModuleHandle("kernel32.dll"), "CreateHardLinkA");
+ if (!create_hard_link)
+ create_hard_link = (T)-1;
+ }
+ if (create_hard_link == (T)-1) {
+ errno = ENOSYS;
+ return -1;
+ }
+ if (!create_hard_link(newpath, oldpath, NULL)) {
+ errno = err_win_to_posix(GetLastError());
+ return -1;
+ }
+ return 0;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index a52e657c51..762eb143a7 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -21,12 +21,12 @@ typedef int pid_t;
#define WEXITSTATUS(x) ((x) & 0xff)
#define WIFSIGNALED(x) ((unsigned)(x) > 259)
-#define SIGKILL 0
-#define SIGCHLD 0
-#define SIGPIPE 0
-#define SIGHUP 0
-#define SIGQUIT 0
-#define SIGALRM 100
+#define SIGHUP 1
+#define SIGQUIT 3
+#define SIGKILL 9
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGCHLD 17
#define F_GETFD 1
#define F_SETFD 2
@@ -67,8 +67,6 @@ static inline int readlink(const char *path, char *buf, size_t bufsiz)
{ errno = ENOSYS; return -1; }
static inline int symlink(const char *oldpath, const char *newpath)
{ errno = ENOSYS; return -1; }
-static inline int link(const char *oldpath, const char *newpath)
-{ errno = ENOSYS; return -1; }
static inline int fchmod(int fildes, mode_t mode)
{ errno = ENOSYS; return -1; }
static inline int fork(void)
@@ -134,6 +132,7 @@ int getpagesize(void); /* defined in MinGW's libgcc.a */
struct passwd *getpwuid(int 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);
/*
* replacements of existing functions
@@ -160,24 +159,22 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
int mingw_rename(const char*, const char*);
#define rename mingw_rename
+#ifdef USE_WIN32_MMAP
+int mingw_getpagesize(void);
+#define getpagesize mingw_getpagesize
+#endif
+
/* Use mingw_lstat() instead of lstat()/stat() and
* mingw_fstat() instead of fstat() on Windows.
- * struct stat is redefined because it lacks the st_blocks member.
*/
-struct mingw_stat {
- unsigned st_mode;
- time_t st_mtime, st_atime, st_ctime;
- unsigned st_dev, st_ino, st_uid, st_gid;
- size_t st_size;
- size_t st_blocks;
-};
-int mingw_lstat(const char *file_name, struct mingw_stat *buf);
-int mingw_fstat(int fd, struct mingw_stat *buf);
+#define off_t off64_t
+#define stat _stati64
+#define lseek _lseeki64
+int mingw_lstat(const char *file_name, struct stat *buf);
+int mingw_fstat(int fd, struct stat *buf);
#define fstat mingw_fstat
#define lstat mingw_lstat
-#define stat mingw_stat
-static inline int mingw_stat(const char *file_name, struct mingw_stat *buf)
-{ return mingw_lstat(file_name, buf); }
+#define _stati64(x,y) mingw_lstat(x,y)
int mingw_utime(const char *file_name, const struct utimbuf *times);
#define utime mingw_utime
diff --git a/compat/regex/regex.c b/compat/regex/regex.c
index 87b33e4669..5ea007567d 100644
--- a/compat/regex/regex.c
+++ b/compat/regex/regex.c
@@ -1043,7 +1043,7 @@ regex_compile (pattern, size, syntax, bufp)
they can be reliably used as array indices. */
register unsigned char c, c1;
- /* A random tempory spot in PATTERN. */
+ /* A random temporary spot in PATTERN. */
const char *p1;
/* Points to the end of the buffer, where we should append. */
@@ -1796,7 +1796,7 @@ regex_compile (pattern, size, syntax, bufp)
we're all done, the pattern will look like:
set_number_at <jump count> <upper bound>
set_number_at <succeed_n count> <lower bound>
- succeed_n <after jump addr> <succed_n count>
+ succeed_n <after jump addr> <succeed_n count>
<body of loop>
jump_n <succeed_n addr> <jump count>
(The upper bound and `jump_n' are omitted if
diff --git a/compat/win32.h b/compat/win32.h
new file mode 100644
index 0000000000..c26384e595
--- /dev/null
+++ b/compat/win32.h
@@ -0,0 +1,34 @@
+/* common Win32 functions for MinGW and Cygwin */
+#include <windows.h>
+
+static inline int file_attr_to_st_mode (DWORD attr)
+{
+ int fMode = S_IREAD;
+ if (attr & FILE_ATTRIBUTE_DIRECTORY)
+ fMode |= S_IFDIR;
+ else
+ fMode |= S_IFREG;
+ if (!(attr & FILE_ATTRIBUTE_READONLY))
+ fMode |= S_IWRITE;
+ return fMode;
+}
+
+static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata)
+{
+ if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata))
+ return 0;
+
+ switch (GetLastError()) {
+ case ERROR_ACCESS_DENIED:
+ case ERROR_SHARING_VIOLATION:
+ case ERROR_LOCK_VIOLATION:
+ case ERROR_SHARING_BUFFER_EXCEEDED:
+ return EACCES;
+ case ERROR_BUFFER_OVERFLOW:
+ return ENAMETOOLONG;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ return ENOMEM;
+ default:
+ return ENOENT;
+ }
+}
diff --git a/compat/win32mmap.c b/compat/win32mmap.c
new file mode 100644
index 0000000000..779d796cd5
--- /dev/null
+++ b/compat/win32mmap.c
@@ -0,0 +1,53 @@
+#include "../git-compat-util.h"
+
+/*
+ * Note that this doesn't return the actual pagesize, but
+ * the allocation granularity. If future Windows specific git code
+ * needs the real getpagesize function, we need to find another solution.
+ */
+int mingw_getpagesize(void)
+{
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ return si.dwAllocationGranularity;
+}
+
+void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
+{
+ HANDLE hmap;
+ void *temp;
+ size_t len;
+ struct stat st;
+ uint64_t o = offset;
+ uint32_t l = o & 0xFFFFFFFF;
+ uint32_t h = (o >> 32) & 0xFFFFFFFF;
+
+ if (!fstat(fd, &st))
+ len = xsize_t(st.st_size);
+ else
+ die("mmap: could not determine filesize");
+
+ if ((length + offset) > len)
+ length = len - offset;
+
+ if (!(flags & MAP_PRIVATE))
+ die("Invalid usage of mmap when built with USE_WIN32_MMAP");
+
+ hmap = CreateFileMapping((HANDLE)_get_osfhandle(fd), 0, PAGE_WRITECOPY,
+ 0, 0, 0);
+
+ if (!hmap)
+ return MAP_FAILED;
+
+ temp = MapViewOfFileEx(hmap, FILE_MAP_COPY, h, l, length, start);
+
+ if (!CloseHandle(hmap))
+ warning("unable to close file mapping handle\n");
+
+ return temp ? temp : MAP_FAILED;
+}
+
+int git_munmap(void *start, size_t length)
+{
+ return !UnmapViewOfFile(start);
+}
diff --git a/compat/winansi.c b/compat/winansi.c
index e2d96dfe6f..44dc293ad3 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -18,8 +18,6 @@
This file is git-specific. Therefore, this file does not attempt
to implement any codes that are not used by git.
-
- TODO: K
*/
static HANDLE console;
@@ -79,6 +77,20 @@ static void set_console_attr(void)
SetConsoleTextAttribute(console, attributes);
}
+static void erase_in_line(void)
+{
+ CONSOLE_SCREEN_BUFFER_INFO sbi;
+
+ if (!console)
+ return;
+
+ GetConsoleScreenBufferInfo(console, &sbi);
+ FillConsoleOutputCharacterA(console, ' ',
+ sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition,
+ NULL);
+}
+
+
static const char *set_attr(const char *str)
{
const char *func;
@@ -218,7 +230,7 @@ static const char *set_attr(const char *str)
set_console_attr();
break;
case 'K':
- /* TODO */
+ erase_in_line();
break;
default:
/* Unsupported code */