/* * Public domain * * BSD socket emulation code for Winsock2 * File IO compatibility shims * Brent Cook * Kinichiro Inoguchi */ #define NO_REDEF_POSIX_FUNCTIONS #include #include #include #include #include #include #include #include #include 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 #include 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