From 4bbc3f4286b19d395f869b74e45004e0316c3bb0 Mon Sep 17 00:00:00 2001 From: Ron Koenderink Date: Tue, 14 Aug 2007 03:33:28 +0000 Subject: [PATCH] Simple POSIX I/O emulation layer to work around Windows's defective Unix I/O: [_WIN32] (socklen_t, accept, posix_accept, bind. posix_bind, listen) (posix_listen, setsockopt, posix_setsockopt, shutdown, posix_shutdown) (socket, posix_socket, close, posix_close, creat, fstat, posix_fstat) (lseek, posix_lseek, open, posix_open, read, posix_read, write) (posix_write, fileno, posix_fileno, fcntl, O_NONBLOCK, F_RDLCK) (F_WRLCK, F_GETFL, F_SETFL, F_SETLK, EWOULDBLOCK, ENOTSOCK) (flock, fsync, posix_fsync): New. (ef_open, io_close, io_input, io_output, io_shutdown, io_noblocking) (player_accept): Use them to simplify. [_WIN32] (posix_fd2socket): New. (empth_select): Use it. (gen_power): Use it. --- src/lib/commands/add.c | 4 - src/lib/commands/new.c | 5 - src/lib/commands/powe.c | 16 +- src/lib/commands/turn.c | 4 - src/lib/common/file.c | 17 +- src/lib/common/fsize.c | 2 - src/lib/common/log.c | 5 - src/lib/common/wantupd.c | 5 - src/lib/empthread/ntthread.c | 17 +- src/lib/gen/emp_config.c | 4 - src/lib/gen/io.c | 45 +-- src/lib/player/accept.c | 4 +- src/lib/player/empdis.c | 2 - src/lib/player/player.c | 2 - src/lib/subs/wu.c | 5 +- src/lib/w32/posixio.c | 565 +++++++++++++++++++++++++++++++++++ src/lib/w32/unistd.h | 76 +++++ 17 files changed, 669 insertions(+), 109 deletions(-) create mode 100644 src/lib/w32/posixio.c diff --git a/src/lib/commands/add.c b/src/lib/commands/add.c index 89e011b6e..45c7114d3 100644 --- a/src/lib/commands/add.c +++ b/src/lib/commands/add.c @@ -34,11 +34,7 @@ #include #include -#if defined(_WIN32) -#include -#else #include -#endif #include #include "commands.h" diff --git a/src/lib/commands/new.c b/src/lib/commands/new.c index 9fc9480af..b0116eb60 100644 --- a/src/lib/commands/new.c +++ b/src/lib/commands/new.c @@ -34,13 +34,8 @@ #include #include -#if defined(_WIN32) -#include -#endif #include -#if !defined(_WIN32) #include -#endif #include "commands.h" #include "land.h" #include "optlist.h" diff --git a/src/lib/commands/powe.c b/src/lib/commands/powe.c index b05be45eb..a66065f32 100644 --- a/src/lib/commands/powe.c +++ b/src/lib/commands/powe.c @@ -35,11 +35,8 @@ */ #include - +#include #include -#ifdef _WIN32 -#include -#endif #include "commands.h" #include "item.h" @@ -317,14 +314,13 @@ gen_power(struct powstr *powbuf, int save) return; for (i = 0; i < MAXNOC; i++) putpower(i, &powbuf[i]); -#ifdef _WIN32 /* - * At least some versions of Windows fail to update mtime on - * write(). Bad, because `power' displays that time. Attempt to - * force an update. + * At least some versions of Windows fail to update st_mtime on + * write(), the st_mtime is not until the file is written to the + * disk. Bad, because `power' displays that time. + * Force a sync to ensure the st_time is correct. */ - _commit(empfile[EF_POWER].fd); -#endif + fsync(empfile[EF_POWER].fd); } static int diff --git a/src/lib/commands/turn.c b/src/lib/commands/turn.c index 4b24b4ded..259434123 100644 --- a/src/lib/commands/turn.c +++ b/src/lib/commands/turn.c @@ -34,11 +34,7 @@ #include #include -#if !defined(_WIN32) #include -#elif defined(__GNUC__) -#include -#endif #include "tel.h" #include "commands.h" #include "optlist.h" diff --git a/src/lib/common/file.c b/src/lib/common/file.c index 3a9488c25..f7e25b4d3 100644 --- a/src/lib/common/file.c +++ b/src/lib/common/file.c @@ -36,17 +36,11 @@ #include #include -#if defined(_WIN32) -#include -#include -#endif #include #include #include #include -#if !defined(_WIN32) #include -#endif #include "file.h" #include "match.h" #include "misc.h" @@ -68,9 +62,7 @@ int ef_open(int type, int how) { struct empfile *ep; -#if !defined(_WIN32) struct flock lock; -#endif int oflags, fd, fsiz, size; if (ef_check(type) < 0) @@ -89,13 +81,7 @@ ef_open(int type, int how) oflags |= O_CREAT | O_TRUNC; #if defined(_WIN32) oflags |= O_BINARY; - if ((fd = sopen(ep->file, oflags, - how & EFF_RDONLY ? SH_DENYNO : SH_DENYWR, - S_IRWUG)) < 0) { - logerror("Can't open %s (%s)", ep->file, strerror(errno)); - return 0; - } -#else +#endif if ((fd = open(ep->file, oflags, S_IRWUG)) < 0) { logerror("Can't open %s (%s)", ep->file, strerror(errno)); return 0; @@ -109,7 +95,6 @@ ef_open(int type, int how) close(fd); return 0; } -#endif /* get file size */ fsiz = fsize(fd); diff --git a/src/lib/common/fsize.c b/src/lib/common/fsize.c index 0107231ed..34cad2c0b 100644 --- a/src/lib/common/fsize.c +++ b/src/lib/common/fsize.c @@ -37,9 +37,7 @@ #include #include -#if !defined(_WIN32) #include -#endif #include "prototypes.h" diff --git a/src/lib/common/log.c b/src/lib/common/log.c index 52869112c..50cf3d247 100644 --- a/src/lib/common/log.c +++ b/src/lib/common/log.c @@ -33,12 +33,7 @@ #include -#if defined(_WIN32) -#include -#endif -#if !defined(_WIN32) #include -#endif #include #include #include diff --git a/src/lib/common/wantupd.c b/src/lib/common/wantupd.c index 439b33af8..439a92948 100644 --- a/src/lib/common/wantupd.c +++ b/src/lib/common/wantupd.c @@ -35,13 +35,8 @@ #include #include -#if defined(_WIN32) -#include -#endif #include -#if !defined(_WIN32) #include -#endif #include "file.h" #include "game.h" #include "misc.h" diff --git a/src/lib/empthread/ntthread.c b/src/lib/empthread/ntthread.c index 878c19407..1bb294537 100644 --- a/src/lib/empthread/ntthread.c +++ b/src/lib/empthread/ntthread.c @@ -55,6 +55,10 @@ #undef NS_ALL #include #include +/* Note: unistd.h(posixio.c) is not thread-safe. + * It may be used *only* while holding hThreadMutex. + */ +#include "unistd.h" #include "misc.h" #include "empthread.h" #include "prototypes.h" @@ -313,6 +317,9 @@ loc_Exit_Handler(DWORD fdwCtrlType) * * This is the main line of each thread. * This is really a static local func.... + * Note: As the POSIX compatibility layer is not thread safe + * this function can not open or create any files or sockets until + * loc_RunThisThread() is called */ static void empth_threadMain(void *pvData) @@ -535,6 +542,7 @@ empth_terminate(empth_t *pThread) void empth_select(int fd, int flags) { + int handle; WSAEVENT hEventObject[2]; empth_t *pThread = TlsGetValue(dwTLSIndex); @@ -545,10 +553,13 @@ empth_select(int fd, int flags) hEventObject[0] = WSACreateEvent(); hEventObject[1] = pThread->hThreadEvent; + handle = posix_fd2socket(fd); + CANT_HAPPEN(handle < 0); + if (flags == EMPTH_FD_READ) - WSAEventSelect(fd, hEventObject[0], FD_READ | FD_ACCEPT | FD_CLOSE); + WSAEventSelect(handle, hEventObject[0], FD_READ | FD_ACCEPT | FD_CLOSE); else if (flags == EMPTH_FD_WRITE) - WSAEventSelect(fd, hEventObject[0], FD_WRITE | FD_CLOSE); + WSAEventSelect(handle, hEventObject[0], FD_WRITE | FD_CLOSE); else { logerror("bad flag %d passed to empth_select", flags); empth_exit(); @@ -556,7 +567,7 @@ empth_select(int fd, int flags) WSAWaitForMultipleEvents(2, hEventObject, FALSE, WSA_INFINITE, FALSE); - WSAEventSelect(fd, hEventObject[0], 0); + WSAEventSelect(handle, hEventObject[0], 0); WSACloseEvent(hEventObject[0]); diff --git a/src/lib/gen/emp_config.c b/src/lib/gen/emp_config.c index 10cedc8f0..37ba63ba3 100644 --- a/src/lib/gen/emp_config.c +++ b/src/lib/gen/emp_config.c @@ -48,11 +48,7 @@ #include #include #include -#ifdef _WIN32 -#include -#else #include -#endif #include "file.h" #include "misc.h" diff --git a/src/lib/gen/io.c b/src/lib/gen/io.c index 8744df63d..ef83f6dd7 100644 --- a/src/lib/gen/io.c +++ b/src/lib/gen/io.c @@ -47,13 +47,12 @@ #include #ifdef _WIN32 #include -#undef NS_ALL #else #include #include #include -#include #endif +#include #include #include "empio.h" @@ -111,11 +110,7 @@ io_close(struct iop *iop) ioq_destroy(iop->input); if (iop->output != 0) ioq_destroy(iop->output); -#if !defined(_WIN32) (void)close(iop->fd); -#else - closesocket(iop->fd); -#endif free(iop); } @@ -135,7 +130,6 @@ io_input(struct iop *iop, int waitforinput) if (waitforinput) { empth_select(iop->fd, EMPTH_FD_READ); } -#if !defined(_WIN32) /* Do the actual read. */ cc = read(iop->fd, buf, sizeof(buf)); if (cc < 0) { @@ -147,19 +141,6 @@ io_input(struct iop *iop, int waitforinput) iop->flags |= IO_ERROR; return -1; } -#else - cc = recv(iop->fd, buf, sizeof(buf), 0); - if (cc == SOCKET_ERROR) { - int err = WSAGetLastError(); - /* Hmm, it would block. file is opened noblock, soooooo.. */ - if (err == WSAEWOULDBLOCK) - return 0; - - /* Some form of file error occurred... */ - iop->flags |= IO_ERROR; - return -1; - } -#endif /* We eof'd */ if (cc == 0) { @@ -232,6 +213,9 @@ io_output(struct iop *iop, int waitforoutput) /* Do the actual write. */ #if !defined(_WIN32) cc = writev(iop->fd, iov, n); +#else + cc = write(iop->fd, buf, n); +#endif /* if it failed.... */ if (cc < 0) { @@ -244,22 +228,6 @@ io_output(struct iop *iop, int waitforoutput) iop->flags |= IO_ERROR; return -1; } -#else - cc = send(iop->fd, buf, n, 0); - - /* if it failed.... */ - if (cc == SOCKET_ERROR) { - int err = WSAGetLastError(); - /* Hmm, it would block. file is opened noblock, soooooo.. */ - if (err == WSAEWOULDBLOCK) { - /* If there are remaining bytes, set the IO as remaining.. */ - remain = ioq_qsize(iop->output); - return remain; - } - iop->flags |= IO_ERROR; - return -1; - } -#endif /* If no bytes were written, something happened.. Like an EOF. */ if (cc == 0) { @@ -366,7 +334,6 @@ io_shutdown(struct iop *iop, int flags) int io_noblocking(struct iop *iop, int value) { -#if !defined(_WIN32) int flags; flags = fcntl(iop->fd, F_GETFL, 0); @@ -378,10 +345,6 @@ io_noblocking(struct iop *iop, int value) flags |= O_NONBLOCK; if (fcntl(iop->fd, F_SETFL, flags) < 0) return -1; -#else - u_long arg = value; - ioctlsocket(iop->fd, FIONBIO, &arg); -#endif if (value == 0) iop->flags &= ~IO_NBLOCK; else diff --git a/src/lib/player/accept.c b/src/lib/player/accept.c index 9249adf0d..2255164cf 100644 --- a/src/lib/player/accept.c +++ b/src/lib/player/accept.c @@ -47,8 +47,8 @@ #include #include #include -#include #endif +#include #include #include #include @@ -170,7 +170,7 @@ player_accept(void *unused) void *inaddr; int s = player_socket; struct player *np; - int len; + socklen_t len; int ns; int set = 1; int stacksize; diff --git a/src/lib/player/empdis.c b/src/lib/player/empdis.c index b37ea4b05..2e2dc267a 100644 --- a/src/lib/player/empdis.c +++ b/src/lib/player/empdis.c @@ -38,9 +38,7 @@ #include #include #include -#if !defined(_WIN32) #include -#endif #include #include "com.h" diff --git a/src/lib/player/player.c b/src/lib/player/player.c index 9f57dbf28..a52d8608a 100644 --- a/src/lib/player/player.c +++ b/src/lib/player/player.c @@ -32,9 +32,7 @@ */ #include -#if !defined(_WIN32) #include -#endif #include #include #include diff --git a/src/lib/subs/wu.c b/src/lib/subs/wu.c index 23a503da2..85fccc560 100644 --- a/src/lib/subs/wu.c +++ b/src/lib/subs/wu.c @@ -33,14 +33,11 @@ #include -#if defined(_WIN32) -#include -#endif #include #include #include -#if !defined(_WIN32) #include +#if !defined(_WIN32) #include #endif #include "file.h" diff --git a/src/lib/w32/posixio.c b/src/lib/w32/posixio.c new file mode 100644 index 000000000..d7e88b63c --- /dev/null +++ b/src/lib/w32/posixio.c @@ -0,0 +1,565 @@ +/* + * Empire - A multi-player, client/server Internet based war game. + * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak, + * Ken Stevens, Steve McClure + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * --- + * + * See files README, COPYING and CREDITS in the root of the source + * tree for related information and legal notices. It is expected + * that future projects/authors will amend these files as needed. + * + * --- + * + * posixio.c: POSIX IO emulation layer for WIN32 + * + * Known contributors to this file: + * Ron Koenderink, 2007 + */ + +/* + * POSIX has just one kind of file descriptors, while Windows has (at + * least) two: one for sockets and one for files, with separate + * functions to operate on them. To present a more POSIX-like + * interface to our application code, we provide a compatibility layer + * that maps POSIX file descriptors to sockets and file handles behind + * the scenes. This actual mapping is done by the fdmap. It doesn't + * implement the finer points of POSIX correctly. In particular, the + * actual values of the file descriptors usually differ. + */ + +#include +#include +#undef NS_ALL +#include +#include +#include +#include +#include + +#include + +#include "unistd.h" +#include "empio.h" +#include "prototypes.h" + +/* + * FD_SETSIZE is the size for the maximum number of sockets. + * The number of file descriptors is in a variable _nhandle + * based on the assertion output. In order the simplify the + * code and skip dynamic allocation, used double the socket size. + */ +#define MAX_FDS (FD_SETSIZE * 2) + +enum fdmap_io_type { + FDMAP_IO_NOTUSED = 0, + FDMAP_IO_FILE, + FDMAP_IO_SOCKET, + FDMAP_IO_ANY /* used for searching only (lookup_handle) */ +}; + +struct fdmap { + int handle; + enum fdmap_io_type type; +}; + +static struct fdmap fdmap[MAX_FDS] = { + {0, FDMAP_IO_FILE}, + {1, FDMAP_IO_FILE}, + {2, FDMAP_IO_FILE} +}; +static int nfd = 3; + +/* + * Allocate a POSIX equivalent file descriptor. + * Note once get_fd() is called either free_fd() or set_fd() + * must be called before thread mutex is released as the + * allocation/deallocation code is not thread safe. + */ +static int +get_fd(void) +{ + int fd; + + for (fd = 0; fd < nfd && fdmap[fd].type != FDMAP_IO_NOTUSED; fd++) ; + if (fd == MAX_FDS) { + errno = EMFILE; + return -1; + } + if (fd == nfd) { + fdmap[fd].type = FDMAP_IO_NOTUSED; + nfd++; + } + return fd; +} + +/* + * Deallocate a POSIX equivalent file descriptor. + */ +static void +free_fd(int fd) +{ + fdmap[fd].type = FDMAP_IO_NOTUSED; + for(; fdmap[nfd - 1].type == FDMAP_IO_NOTUSED; nfd--) ; +} + +/* + * Complete the allocation of the file descriptor. + */ +static void +set_fd(int fd, enum fdmap_io_type type, int handle) +{ + int i; + + fdmap[fd].handle = handle; + fdmap[fd].type = type; + + /* + * Garbage collection for posix_fileno(), currently not + * replacing fclose() and fcloseall() so do not know when + * a stream is closed. + */ + for (i = 0; i < nfd; i++) { + if (i != fd && type == fdmap[i].type && handle == fdmap[i].handle) + free_fd(i); + } +} + +/* + * Find the windows handle (file or socket) for file descriptor. + * Return windows handle and type of handle. + * You can search for a specific type (FDMAP_IO_FILE or FDMAP_IO_SOCKET) + * or for both search by using FDMAP_IO_ANY. + * FDMAP_IO_NOTUSED is not valid type to search with. + */ +static int +lookup_handle(int fd, enum fdmap_io_type d_type, int error, + enum fdmap_io_type *type_ptr, int *handle_ptr) +{ + + if (fd < 0 || fd >= MAX_FDS) { + if (error != 0) + errno = error; + return 0; + } else if ((fdmap[fd].type != d_type && d_type != FDMAP_IO_ANY) || + (fdmap[fd].type == FDMAP_IO_NOTUSED && d_type == FDMAP_IO_ANY)) { + if (error != 0) + errno = error; + return 0; + } + if (type_ptr != NULL) + *type_ptr = fdmap[fd].type; + if (handle_ptr != NULL) + *handle_ptr = fdmap[fd].handle; + return 1; +} + +/* + * Find and return the file descriptor associated with windows handle. + * You can search for FDMAP_IO_FILE or FDMAP_IO_SOCKET. + * FDMAP_IO_ANY or FDMAP_IO_NOTUSED is not considered valid search + * criteria. + */ +static int +lookup_fd(int handle, enum fdmap_io_type d_type) +{ + int i; + + for (i = 0; i < nfd; i++) + if (fdmap[i].handle == handle && fdmap[i].type == d_type) + return i; + return -1; +} + +/* + * Get the window socket handle for POSIX file descriptor. + */ +int +posix_fd2socket(int fd) +{ + int handle; + enum dmap_io_type type; + + if (!lookup_handle(fd, FDMAP_IO_SOCKET, WSAENOTSOCK, + &type, &handle)) + return INVALID_SOCKET; + return handle; +} + +#define SOCKET_FUNCTION(expr) \ + int result; \ + int handle; \ + \ + if (!lookup_handle(fd, FDMAP_IO_SOCKET, \ + ENOTSOCK, NULL, &handle)) \ + return -1; \ + \ + result = (expr); \ + if (result == SOCKET_ERROR) { \ + errno = WSAGetLastError(); \ + return -1; \ + } \ + return result; + +/* + * POSIX equivalent for accept(). + */ +#undef accept +int +posix_accept(int fd, struct sockaddr *addr, socklen_t *addrlen) +{ + int new_fd; + int handle, new_handle; + + if (!lookup_handle(fd, FDMAP_IO_SOCKET, ENOTSOCK, NULL, &handle)) + return -1; + + new_fd = get_fd(); + if (new_fd < 0) + return -1; + + new_handle = accept(handle, addr, addrlen); + if (new_handle == INVALID_SOCKET) { + free_fd(new_fd); + errno = WSAGetLastError(); + return -1; + } + set_fd(new_fd, FDMAP_IO_SOCKET, new_handle); + return new_fd; +} + +/* + * POSIX equivalent for bind(). + */ +#undef bind +int +posix_bind(int fd, const struct sockaddr *name, int namelen) +{ + SOCKET_FUNCTION(bind(handle, name, namelen)) +} + +/* + * POSIX equivalent for listen(). + */ +#undef listen +int +posix_listen(int fd, int backlog) +{ + SOCKET_FUNCTION(listen(handle, backlog)) +} + +/* + * POSIX equivalent for setsockopt(). + */ +#undef setsockopt +int +posix_setsockopt(int fd, int level, int optname, + const char *optval, int optlen) +{ + SOCKET_FUNCTION(setsockopt(handle, level, optname, + optval, optlen)) +} + +/* + * POSIX equivalent for shutdown(). + */ +#undef shutdown +int +posix_shutdown(int fd, int how) +{ + SOCKET_FUNCTION(shutdown(handle, how)) +} + +/* + * POSIX equivalent for socket(). + */ +#undef socket +int +posix_socket(int domain, int type, int protocol) +{ + int handle; + int new_fd; + + if ((new_fd = get_fd()) < 0) + return -1; + + handle = socket(domain, type, protocol); + if (handle == INVALID_SOCKET) { + free_fd(new_fd); + errno = WSAGetLastError(); + return -1; + } + set_fd(new_fd, FDMAP_IO_SOCKET, handle); + return new_fd; +} + +#define FILE_FUNCTION(type, expr) \ + int handle; \ + \ + if (!lookup_handle(fd, (type), EBADF, NULL, &handle)) \ + return -1; \ + \ + return (expr); + +/* + * POSIX equivalent for close(). + */ +int +posix_close(int fd) +{ + int result; + int handle; + enum fdmap_io_type type; + + if (!lookup_handle(fd, FDMAP_IO_ANY, EBADF, &type, &handle)) + return -1; + + free_fd(fd); + switch (type) { + case FDMAP_IO_SOCKET: + result = closesocket(handle); + if (result == SOCKET_ERROR) { + errno = WSAGetLastError(); + return -1; + } + return result; + case FDMAP_IO_FILE: + return _close(handle); + } + CANT_REACH(); + return -1; +} + +/* + * posix_fsync forces file sync with the disk. + * In order for the power report report to accurate timestamp, + * the _commit() is to force a sync with disk and therefore + * an update for file time. + */ +int +posix_fsync(int fd) +{ + FILE_FUNCTION(FDMAP_IO_FILE, _commit(handle)) +} + +/* + * POSIX equivalent for fstat(). + * fstat() is used instead of _fstat(), + * otherwise problems with the 32/64 time definitions + * in WIN32. + */ +#undef fstat +int +posix_fstat(int fd, struct stat *buffer) +{ + FILE_FUNCTION(FDMAP_IO_ANY, fstat(handle, buffer)) +} + +/* + * POSIX equivalent for lseek(). + */ +int +posix_lseek(int fd, long offset, int origin) +{ + FILE_FUNCTION(FDMAP_IO_FILE, _lseek(handle, offset, origin)) +} + +/* + * POSIX equivalent for open(). + * Implements file locks when opening files to provide equivalent + * F_GETLK/F_SETLK. + */ +int +posix_open(const char *fname, int oflag, ...) +{ + va_list ap; + int pmode = 0, new_fd; + int handle; + + if (oflag & O_CREAT) { + va_start(ap, oflag); + pmode = va_arg(ap, int); + va_end(ap); + } + + if ((new_fd = get_fd()) < 0) + return -1; + + /* + * We don't implement fcntl() for F_SETLK. Instead, we lock *all* + * files we open. Not ideal, but it works for Empire. + */ + _sopen_s(&handle, fname, oflag, + oflag & O_RDONLY ? SH_DENYNO : SH_DENYWR, pmode); + if (handle == -1) { + free_fd(new_fd); + return -1; + } + set_fd(new_fd, FDMAP_IO_FILE, handle); + return new_fd; +} + +#define SHARED_FUNCTION(socket_expr, file_expr) \ + int result; \ + int handle; \ + enum fdmap_io_type type; \ + \ + if (!lookup_handle(fd, FDMAP_IO_ANY, EBADF, &type, &handle)) \ + return -1; \ + \ + switch (type) { \ + case FDMAP_IO_SOCKET: \ + result = (socket_expr); \ + if (result == SOCKET_ERROR) { \ + errno = WSAGetLastError(); \ + return -1; \ + } \ + return result; \ + case FDMAP_IO_FILE: \ + return (file_expr); \ + } \ + CANT_REACH(); \ + return -1; + +/* + * POSIX equivalent for read(). + */ +int +posix_read(int fd, void *buffer, unsigned int count) +{ + SHARED_FUNCTION(recv(handle, buffer, count, 0), + _read(handle, buffer, count)) +} + +/* + * POSIX equivalent for write(). + */ +int +posix_write(int fd, const void *buffer, unsigned int count) +{ + SHARED_FUNCTION(send(handle, buffer, count, 0), + _write(handle, buffer, count)) +} + +/* + * POSIX equivalent for fileno(). + * As fopen/fclose/fcloseall are not implemented as POSIX + * equivalent functions, the mapping is done when required + * by a call to fileno(). The garbage collection of the + * file descriptors allocated is done in set_fd() when the + * handle is reused. + */ +int +posix_fileno(FILE *stream) +{ + int fd; + int handle; + + if (stream == NULL) { + errno = EBADF; + return -1; + } + + handle = _fileno(stream); + + fd = lookup_fd(handle, FDMAP_IO_FILE); + if (fd >= 0) + return fd; + + if ((fd = get_fd()) < 0) { + errno = EBADF; + return -1; + } + + set_fd(fd, FDMAP_IO_FILE, handle); + return fd; +} + +/* + * POSIX equivalent for fcntl(). + * Currently supports only the F_GETFL/F_SETFL/O_NONBLOCK + * Currently ignores F_GETLK/F_SETLK as the file locks are + * implement in open() + */ +int +fcntl(int fd, int cmd, ...) +{ + va_list ap; + int value; + unsigned int nonblocking; + int result; + long bytes_returned; + int handle; + enum fdmap_io_type type; + + if (!lookup_handle(fd, FDMAP_IO_ANY, EBADF, &type, &handle)) + return -1; + + switch (cmd) + { + case F_GETFL: + /* + * F_GETFL and F_SETFL only support O_NONBLOCK + * for sockets currently + */ + if (type == FDMAP_IO_SOCKET) { + result = WSAIoctl(handle, FIONBIO, NULL, 0,&nonblocking, + sizeof (nonblocking), &bytes_returned, NULL, NULL); + + if(result < 0) { + errno = WSAGetLastError(); + return -1; + } + + if (nonblocking) + return O_NONBLOCK; + else + return 0; + } + break; + case F_SETFL: + if (type == FDMAP_IO_SOCKET) { + va_start(ap, cmd); + value = va_arg(ap, int); + va_end(ap); + if (value & O_NONBLOCK) + nonblocking = 1; + else + nonblocking = 0; + + result = WSAIoctl(handle, FIONBIO, &nonblocking, + sizeof (nonblocking), NULL, 0, &bytes_returned, + NULL, NULL); + + if(result < 0) { + errno = WSAGetLastError(); + return -1; + } + return result; + } + break; + case F_SETLK: + /* + * The POSIX equivalent is not available in WIN32 + * That implement the file locking in the file open + * by using sopen instead of open. + */ + return 0; + } + errno = EINVAL; + return -1; +} diff --git a/src/lib/w32/unistd.h b/src/lib/w32/unistd.h index 80be3c2c1..fd024a0e7 100644 --- a/src/lib/w32/unistd.h +++ b/src/lib/w32/unistd.h @@ -34,7 +34,9 @@ #ifndef UNISTD_H #define UNISTD_H +#include #include "getopt.h" +#include /* * posixfile.c @@ -43,4 +45,78 @@ extern int posix_mkdir(const char *dirname, int perm); +/* + * posixio.c + */ + +typedef int socklen_t; + +#define accept(fd, addr, addrlen) \ + posix_accept((fd), (addr), (addrlen)) +#define bind(fd, name, namelen) \ + posix_bind((fd), (name), (namelen)) +#define listen(fd, backlog) \ + posix_listen((fd), (backlog)) +#define setsockopt(fd, level, optname, optval, optlen) \ + posix_setsockopt((fd), (level), (optname), (optval), (optlen)) +#define shutdown(fd, how) \ + posix_shutdown((fd), (how)) +#define socket(domain, type, protocol) \ + posix_socket((domain), (type), (protocol)) + +#define close(fd) \ + posix_close((fd)) +#define creat(fname, pmode) \ + posix_open((fname), _O_WRONLY | _O_CREAT |_O_TRUNC, (pmode)) +#define fstat(fd, buffer) \ + posix_fstat((fd), (buffer)) +#define lseek(fd, offset, origin) \ + posix_lseek((fd), (offset), (origin)) +#define open(fname, oflag, ...) \ + posix_open((fname), (oflag), __VA_ARGS__) +#define read posix_read +#define write(fd, buffer, count) \ + posix_write((fd), (buffer), (count)) +#define fileno(stream) \ + posix_fileno((stream)) +#define fsync(fd) \ + posix_fsync((fd)) + +#define O_NONBLOCK 1 +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_GETFL 1 +#define F_SETFL 2 +#define F_SETLK 3 +#define EWOULDBLOCK WSAEWOULDBLOCK +#define ENOTSOCK WSAENOTSOCK + +struct flock +{ + int l_type; + int l_whence; + int l_start; + int l_len; +}; + +extern int posix_fd2socket(int fd); + +extern int posix_accept(int fd, struct sockaddr *addr, socklen_t *addrlen); +extern int posix_bind(int fd, const struct sockaddr *name, int namelen); +extern int posix_listen(int fd, int backlog); +extern int posix_setsockopt(int fd, int level, int optname, + const char *optval, int optlen); +extern int posix_shutdown(int fd, int how); +extern int posix_socket(int domain, int type, int protocol); + +extern int posix_close(int fd); +extern int posix_fstat(int fd, struct stat *buffer); +extern int posix_lseek(int fd, long offset, int origin); +extern int posix_open(const char *fname, int oflag, ...); +extern int posix_read(int fd, void *buffer, unsigned int count); +extern int posix_write(int fd, const void *buffer, unsigned int count); + +extern int posix_fileno(FILE *stream); +extern int posix_fsync(int fd); +extern int fcntl(int fd, int cmd, ...); #endif /* UNISTD_H */ -- 2.43.0