about summary refs log tree commit diff
path: root/compat/posix_win.c
diff options
context:
space:
mode:
Diffstat (limited to 'compat/posix_win.c')
-rw-r--r--compat/posix_win.c245
1 files changed, 245 insertions, 0 deletions
diff --git a/compat/posix_win.c b/compat/posix_win.c
new file mode 100644
index 0000000..30c93cd
--- /dev/null
+++ b/compat/posix_win.c
@@ -0,0 +1,245 @@
+/*
+ * Public domain
+ *
+ * BSD socket emulation code for Winsock2
+ * File IO compatibility shims
+ * Brent Cook <bcook@openbsd.org>
+ * Kinichiro Inoguchi <inoguchi@openbsd.org>
+ */
+
+#define NO_REDEF_POSIX_FUNCTIONS
+
+#include <windows.h>
+#include <ws2tcpip.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void
+posix_perror(const char *s)
+{
+	fprintf(stderr, "%s: %s\n", s, strerror(errno));
+}
+
+FILE *
+posix_fopen(const char *path, const char *mode)
+{
+	if (strchr(mode, 'b') == NULL) {
+		char *bin_mode = NULL;
+		if (asprintf(&bin_mode, "%sb", mode) == -1)
+			return NULL;
+		FILE *f = fopen(path, bin_mode);
+		free(bin_mode);
+		return f;
+	}
+
+	return fopen(path, mode);
+}
+
+int
+posix_open(const char *path, ...)
+{
+	va_list ap;
+	int mode = 0;
+	int flags;
+
+	va_start(ap, path);
+	flags = va_arg(ap, int);
+	if (flags & O_CREAT)
+		mode = va_arg(ap, int);
+	va_end(ap);
+
+	flags |= O_BINARY;
+	if (flags & O_CLOEXEC) {
+		flags &= ~O_CLOEXEC;
+		flags |= O_NOINHERIT;
+	}
+	flags &= ~O_NONBLOCK;
+	return open(path, flags, mode);
+}
+
+char *
+posix_fgets(char *s, int size, FILE *stream)
+{
+	char *ret = fgets(s, size, stream);
+	if (ret != NULL) {
+		size_t end = strlen(ret);
+		if (end >= 2 && ret[end - 2] == '\r' && ret[end - 1] == '\n') {
+			ret[end - 2] = '\n';
+			ret[end - 1] = '\0';
+		}
+	}
+	return ret;
+}
+
+int
+posix_rename(const char *oldpath, const char *newpath)
+{
+	return MoveFileEx(oldpath, newpath, MOVEFILE_REPLACE_EXISTING) ? 0 : -1;
+}
+
+static int
+wsa_errno(int err)
+{
+	switch (err) {
+	case WSAENOBUFS:
+		errno = ENOMEM;
+		break;
+	case WSAEACCES:
+		errno = EACCES;
+		break;
+	case WSANOTINITIALISED:
+		errno = EPERM;
+		break;
+	case WSAEHOSTUNREACH:
+	case WSAENETDOWN:
+		errno = EIO;
+		break;
+	case WSAEFAULT:
+		errno = EFAULT;
+		break;
+	case WSAEINTR:
+		errno = EINTR;
+		break;
+	case WSAEINVAL:
+		errno = EINVAL;
+		break;
+	case WSAEINPROGRESS:
+		errno = EINPROGRESS;
+		break;
+	case WSAEWOULDBLOCK:
+		errno = EAGAIN;
+		break;
+	case WSAEOPNOTSUPP:
+		errno = ENOTSUP;
+		break;
+	case WSAEMSGSIZE:
+		errno = EFBIG;
+		break;
+	case WSAENOTSOCK:
+		errno = ENOTSOCK;
+		break;
+	case WSAENOPROTOOPT:
+		errno = ENOPROTOOPT;
+		break;
+	case WSAECONNREFUSED:
+		errno = ECONNREFUSED;
+		break;
+	case WSAEAFNOSUPPORT:
+		errno = EAFNOSUPPORT;
+		break;
+	case WSAEBADF:
+		errno = EBADF;
+		break;
+	case WSAENETRESET:
+	case WSAENOTCONN:
+	case WSAECONNABORTED:
+	case WSAECONNRESET:
+	case WSAESHUTDOWN:
+	case WSAETIMEDOUT:
+		errno = EPIPE;
+		break;
+	}
+	return -1;
+}
+
+int
+posix_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+	int rc = connect(sockfd, addr, addrlen);
+	if (rc == SOCKET_ERROR)
+		return wsa_errno(WSAGetLastError());
+	return rc;
+}
+
+int
+posix_close(int fd)
+{
+	if (closesocket(fd) == SOCKET_ERROR) {
+		int err = WSAGetLastError();
+		return (err == WSAENOTSOCK || err == WSAEBADF ||
+		    err == WSANOTINITIALISED) ?
+			close(fd) : wsa_errno(err);
+	}
+	return 0;
+}
+
+ssize_t
+posix_read(int fd, void *buf, size_t count)
+{
+	ssize_t rc = recv(fd, buf, count, 0);
+	if (rc == SOCKET_ERROR) {
+		int err = WSAGetLastError();
+		return (err == WSAENOTSOCK || err == WSAEBADF ||
+		    err == WSANOTINITIALISED) ?
+			read(fd, buf, count) : wsa_errno(err);
+	}
+	return rc;
+}
+
+ssize_t
+posix_write(int fd, const void *buf, size_t count)
+{
+	ssize_t rc = send(fd, buf, count, 0);
+	if (rc == SOCKET_ERROR) {
+		int err = WSAGetLastError();
+		return (err == WSAENOTSOCK || err == WSAEBADF ||
+		    err == WSANOTINITIALISED) ?
+			write(fd, buf, count) : wsa_errno(err);
+	}
+	return rc;
+}
+
+int
+posix_getsockopt(int sockfd, int level, int optname,
+	void *optval, socklen_t *optlen)
+{
+	int rc = getsockopt(sockfd, level, optname, (char *)optval, optlen);
+	return rc == 0 ? 0 : wsa_errno(WSAGetLastError());
+
+}
+
+int
+posix_setsockopt(int sockfd, int level, int optname,
+	const void *optval, socklen_t optlen)
+{
+	int rc = setsockopt(sockfd, level, optname, (char *)optval, optlen);
+	return rc == 0 ? 0 : wsa_errno(WSAGetLastError());
+}
+
+uid_t getuid(void)
+{
+	/* Windows fstat sets 0 as st_uid */
+	return 0;
+}
+
+#ifdef _MSC_VER
+struct timezone;
+int gettimeofday(struct timeval * tp, struct timezone * tzp)
+{
+	/*
+	 * Note: some broken versions only have 8 trailing zero's, the correct
+	 * epoch has 9 trailing zero's
+	 */
+	static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
+
+	SYSTEMTIME  system_time;
+	FILETIME    file_time;
+	uint64_t    time;
+
+	GetSystemTime(&system_time);
+	SystemTimeToFileTime(&system_time, &file_time);
+	time = ((uint64_t)file_time.dwLowDateTime);
+	time += ((uint64_t)file_time.dwHighDateTime) << 32;
+
+	tp->tv_sec = (long)((time - EPOCH) / 10000000L);
+	tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
+	return 0;
+}
+
+#endif