311 lines
5.5 KiB
C
311 lines
5.5 KiB
C
/*
|
|
* 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;
|
|
}
|
|
|
|
/*
|
|
* Employ a similar trick to cpython (pycore_fileutils.h) where the CRT report
|
|
* handler is disabled while checking if a descriptor is a socket or a file
|
|
*/
|
|
#if defined _MSC_VER && _MSC_VER >= 1900
|
|
|
|
#include <crtdbg.h>
|
|
#include <stdlib.h>
|
|
|
|
static void noop_handler(const wchar_t *expression, const wchar_t *function,
|
|
const wchar_t *file, unsigned int line, uintptr_t pReserved)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#define BEGIN_SUPPRESS_IPH \
|
|
_invalid_parameter_handler old_handler = _set_thread_local_invalid_parameter_handler(noop_handler)
|
|
#define END_SUPPRESS_IPH \
|
|
_set_thread_local_invalid_parameter_handler(old_handler)
|
|
|
|
#else
|
|
|
|
#define BEGIN_SUPPRESS_IPH
|
|
#define END_SUPPRESS_IPH
|
|
|
|
#endif
|
|
|
|
static int
|
|
is_socket(int fd)
|
|
{
|
|
intptr_t hd;
|
|
|
|
BEGIN_SUPPRESS_IPH;
|
|
hd = _get_osfhandle(fd);
|
|
END_SUPPRESS_IPH;
|
|
|
|
if (hd == (intptr_t)INVALID_HANDLE_VALUE) {
|
|
return 1; /* fd is not file descriptor */
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
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)
|
|
{
|
|
int rc;
|
|
|
|
if (is_socket(fd)) {
|
|
if ((rc = closesocket(fd)) == SOCKET_ERROR) {
|
|
int err = WSAGetLastError();
|
|
rc = wsa_errno(err);
|
|
}
|
|
} else {
|
|
rc = close(fd);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
ssize_t
|
|
posix_read(int fd, void *buf, size_t count)
|
|
{
|
|
ssize_t rc;
|
|
|
|
if (is_socket(fd)) {
|
|
if ((rc = recv(fd, buf, count, 0)) == SOCKET_ERROR) {
|
|
int err = WSAGetLastError();
|
|
rc = wsa_errno(err);
|
|
}
|
|
} else {
|
|
rc = read(fd, buf, count);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
ssize_t
|
|
posix_write(int fd, const void *buf, size_t count)
|
|
{
|
|
ssize_t rc;
|
|
if (is_socket(fd)) {
|
|
if ((rc = send(fd, buf, count, 0)) == SOCKET_ERROR) {
|
|
rc = wsa_errno(WSAGetLastError());
|
|
}
|
|
} else {
|
|
rc = write(fd, buf, count);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
posix_getsockopt(int sockfd, int level, int optname,
|
|
void *optval, socklen_t *optlen)
|
|
{
|
|
int rc;
|
|
if (is_socket(sockfd)) {
|
|
rc = getsockopt(sockfd, level, optname, (char *)optval, optlen);
|
|
if (rc != 0) {
|
|
rc = wsa_errno(WSAGetLastError());
|
|
}
|
|
} else {
|
|
rc = -1;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
posix_setsockopt(int sockfd, int level, int optname,
|
|
const void *optval, socklen_t optlen)
|
|
{
|
|
int rc;
|
|
if (is_socket(sockfd)) {
|
|
rc = setsockopt(sockfd, level, optname, (char *)optval, optlen);
|
|
if (rc != 0) {
|
|
rc = wsa_errno(WSAGetLastError());
|
|
}
|
|
} else {
|
|
rc = -1;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
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
|