This commit is contained in:
manojampalam 2016-03-03 23:04:49 -08:00
parent ab8d9f0eda
commit d721cce789
4 changed files with 1224 additions and 1187 deletions

View File

@ -14,519 +14,532 @@
#define errno_from_Win32LastError() errno_from_Win32Error(GetLastError()) #define errno_from_Win32LastError() errno_from_Win32Error(GetLastError())
static int errno_from_Win32Error(int win32_error) static int
errno_from_Win32Error(int win32_error)
{ {
switch (win32_error){ switch (win32_error) {
case ERROR_ACCESS_DENIED: case ERROR_ACCESS_DENIED:
return EACCES; return EACCES;
case ERROR_OUTOFMEMORY: case ERROR_OUTOFMEMORY:
return ENOMEM; return ENOMEM;
case ERROR_FILE_EXISTS: case ERROR_FILE_EXISTS:
return EEXIST; return EEXIST;
case ERROR_FILE_NOT_FOUND: case ERROR_FILE_NOT_FOUND:
return ENOENT; return ENOENT;
default: default:
return EOTHER; return EOTHER;
} }
} }
int pipe_number = 0; static int pipe_number = 0;
int fileio_pipe(struct w32_io* pio[2]) { int
HANDLE read_handle = INVALID_HANDLE_VALUE, write_handle = INVALID_HANDLE_VALUE; fileio_pipe(struct w32_io* pio[2]) {
struct w32_io *pio_read = NULL, *pio_write = NULL; HANDLE read_handle = INVALID_HANDLE_VALUE, write_handle = INVALID_HANDLE_VALUE;
char pipe_name[MAX_PATH]; struct w32_io *pio_read = NULL, *pio_write = NULL;
SECURITY_ATTRIBUTES sec_attributes; char pipe_name[MAX_PATH];
SECURITY_ATTRIBUTES sec_attributes;
if (pio == NULL) { if (pio == NULL) {
errno = EFAULT; errno = EFAULT;
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
return -1; return -1;
} }
if (-1 == sprintf_s(pipe_name, MAX_PATH, "\\\\.\\Pipe\\W32PosixPipe.%08x.%08x", GetCurrentProcessId(), pipe_number++)) { if (-1 == sprintf_s(pipe_name, MAX_PATH, "\\\\.\\Pipe\\W32PosixPipe.%08x.%08x", GetCurrentProcessId(), pipe_number++)) {
errno = EOTHER; errno = EOTHER;
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
goto error; goto error;
} }
sec_attributes.bInheritHandle = TRUE; sec_attributes.bInheritHandle = TRUE;
sec_attributes.lpSecurityDescriptor = NULL; sec_attributes.lpSecurityDescriptor = NULL;
sec_attributes.nLength = 0; sec_attributes.nLength = 0;
read_handle = CreateNamedPipeA(pipe_name, read_handle = CreateNamedPipeA(pipe_name,
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_WAIT, PIPE_TYPE_BYTE | PIPE_WAIT,
1, 1,
4096, 4096,
4096, 4096,
0, 0,
&sec_attributes); &sec_attributes);
if (read_handle == INVALID_HANDLE_VALUE) { if (read_handle == INVALID_HANDLE_VALUE) {
errno = errno_from_Win32LastError(); errno = errno_from_Win32LastError();
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
goto error; goto error;
} }
write_handle = CreateFileA(pipe_name, write_handle = CreateFileA(pipe_name,
GENERIC_WRITE, GENERIC_WRITE,
0, 0,
&sec_attributes, &sec_attributes,
OPEN_EXISTING, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL); NULL);
if (write_handle == INVALID_HANDLE_VALUE) { if (write_handle == INVALID_HANDLE_VALUE) {
errno = errno_from_Win32LastError(); errno = errno_from_Win32LastError();
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
goto error; goto error;
} }
pio_read = (struct w32_io*)malloc(sizeof(struct w32_io)); pio_read = (struct w32_io*)malloc(sizeof(struct w32_io));
pio_write = (struct w32_io*)malloc(sizeof(struct w32_io)); pio_write = (struct w32_io*)malloc(sizeof(struct w32_io));
if (!pio_read || !pio_write) { if (!pio_read || !pio_write) {
errno = ENOMEM; errno = ENOMEM;
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
goto error; goto error;
} }
memset(pio_read, 0, sizeof(struct w32_io)); memset(pio_read, 0, sizeof(struct w32_io));
memset(pio_write, 0, sizeof(struct w32_io)); memset(pio_write, 0, sizeof(struct w32_io));
pio_read->handle = read_handle; pio_read->handle = read_handle;
pio_read->internal.state = PIPE_READ_END; pio_read->internal.state = PIPE_READ_END;
pio_write->handle = write_handle; pio_write->handle = write_handle;
pio_write->internal.state = PIPE_WRITE_END; pio_write->internal.state = PIPE_WRITE_END;
pio[0] = pio_read; pio[0] = pio_read;
pio[1] = pio_write; pio[1] = pio_write;
return 0; return 0;
error: error:
if (read_handle) if (read_handle)
CloseHandle(read_handle); CloseHandle(read_handle);
if (write_handle) if (write_handle)
CloseHandle(write_handle); CloseHandle(write_handle);
if (pio_read) if (pio_read)
free(pio_read); free(pio_read);
if (pio_write) if (pio_write)
free(pio_write); free(pio_write);
return -1; return -1;
} }
struct createFile_flags { struct createFile_flags {
DWORD dwDesiredAccess; DWORD dwDesiredAccess;
DWORD dwShareMode; DWORD dwShareMode;
SECURITY_ATTRIBUTES securityAttributes; SECURITY_ATTRIBUTES securityAttributes;
DWORD dwCreationDisposition; DWORD dwCreationDisposition;
DWORD dwFlagsAndAttributes; DWORD dwFlagsAndAttributes;
}; };
static int createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags){ static int
createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags) {
//check flags //check flags
int rwflags = flags & 0xf; int rwflags = flags & 0xf;
int c_s_flags = flags & 0xfffffff0; int c_s_flags = flags & 0xfffffff0;
//should be one of one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR //should be one of one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR
if ((rwflags != O_RDONLY) && (rwflags != O_WRONLY) && (rwflags != O_RDWR)) { if ((rwflags != O_RDONLY) && (rwflags != O_WRONLY) && (rwflags != O_RDWR)) {
debug("ERROR: wrong rw flags"); debug("ERROR: wrong rw flags");
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
//only following create and status flags currently supported //only following create and status flags currently supported
if (c_s_flags & ~(O_NONBLOCK | O_APPEND | O_CREAT | O_TRUNC | O_EXCL | O_BINARY)) { if (c_s_flags & ~(O_NONBLOCK | O_APPEND | O_CREAT | O_TRUNC | O_EXCL | O_BINARY)) {
debug("ERROR: Unsupported flags: %d", flags); debug("ERROR: Unsupported flags: %d", flags);
errno = ENOTSUP; errno = ENOTSUP;
return -1; return -1;
} }
//validate mode //validate mode
if (mode &~(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) { if (mode &~(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) {
debug("ERROR: unsupported mode: %d", mode); debug("ERROR: unsupported mode: %d", mode);
errno = ENOTSUP; errno = ENOTSUP;
return -1; return -1;
} }
switch (rwflags) { switch (rwflags) {
case O_RDONLY: case O_RDONLY:
cf_flags->dwDesiredAccess = GENERIC_READ; cf_flags->dwDesiredAccess = GENERIC_READ;
break; break;
case O_WRONLY: case O_WRONLY:
cf_flags->dwDesiredAccess = GENERIC_WRITE; cf_flags->dwDesiredAccess = GENERIC_WRITE;
break; break;
case O_RDWR: case O_RDWR:
cf_flags->dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; cf_flags->dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
break; break;
} }
cf_flags->dwShareMode = 0; cf_flags->dwShareMode = 0;
cf_flags->securityAttributes.lpSecurityDescriptor = NULL; cf_flags->securityAttributes.lpSecurityDescriptor = NULL;
cf_flags->securityAttributes.bInheritHandle = TRUE; cf_flags->securityAttributes.bInheritHandle = TRUE;
cf_flags->securityAttributes.nLength = 0; cf_flags->securityAttributes.nLength = 0;
cf_flags->dwCreationDisposition = OPEN_EXISTING; cf_flags->dwCreationDisposition = OPEN_EXISTING;
if (c_s_flags & O_TRUNC) if (c_s_flags & O_TRUNC)
cf_flags->dwCreationDisposition = TRUNCATE_EXISTING; cf_flags->dwCreationDisposition = TRUNCATE_EXISTING;
if (c_s_flags & O_CREAT) { if (c_s_flags & O_CREAT) {
if (c_s_flags & O_EXCL) if (c_s_flags & O_EXCL)
cf_flags->dwCreationDisposition = CREATE_NEW; cf_flags->dwCreationDisposition = CREATE_NEW;
else else
cf_flags->dwCreationDisposition = OPEN_ALWAYS; cf_flags->dwCreationDisposition = OPEN_ALWAYS;
} }
if (c_s_flags & O_APPEND) if (c_s_flags & O_APPEND)
cf_flags->dwDesiredAccess = FILE_APPEND_DATA; cf_flags->dwDesiredAccess = FILE_APPEND_DATA;
cf_flags->dwFlagsAndAttributes = FILE_FLAG_OVERLAPPED | SECURITY_IMPERSONATION; cf_flags->dwFlagsAndAttributes = FILE_FLAG_OVERLAPPED | SECURITY_IMPERSONATION;
//TODO - map mode //TODO - map mode
return 0; return 0;
} }
struct w32_io* fileio_open(const char *pathname, int flags, int mode) { struct w32_io*
struct w32_io* pio = NULL; fileio_open(const char *pathname, int flags, int mode) {
struct createFile_flags cf_flags; struct w32_io* pio = NULL;
HANDLE handle; struct createFile_flags cf_flags;
HANDLE handle;
//check input params //check input params
if (pathname == NULL) { if (pathname == NULL) {
errno = EINVAL; errno = EINVAL;
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
return NULL; return NULL;
} }
if (createFile_flags_setup(flags, mode, &cf_flags) == -1) if (createFile_flags_setup(flags, mode, &cf_flags) == -1)
return NULL; return NULL;
handle = CreateFileA(pathname, cf_flags.dwDesiredAccess, cf_flags.dwShareMode, &cf_flags.securityAttributes, cf_flags.dwCreationDisposition, cf_flags.dwFlagsAndAttributes, NULL); handle = CreateFileA(pathname, cf_flags.dwDesiredAccess, cf_flags.dwShareMode, &cf_flags.securityAttributes, cf_flags.dwCreationDisposition, cf_flags.dwFlagsAndAttributes, NULL);
if (handle == INVALID_HANDLE_VALUE) { if (handle == INVALID_HANDLE_VALUE) {
errno = errno_from_Win32LastError(); errno = errno_from_Win32LastError();
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
return NULL; return NULL;
} }
pio = (struct w32_io*)malloc(sizeof(struct w32_io)); pio = (struct w32_io*)malloc(sizeof(struct w32_io));
if (pio == NULL) { if (pio == NULL) {
CloseHandle(handle); CloseHandle(handle);
errno = ENOMEM; errno = ENOMEM;
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
return NULL; return NULL;
} }
memset(pio, 0, sizeof(struct w32_io)); memset(pio, 0, sizeof(struct w32_io));
if (flags & O_NONBLOCK) if (flags & O_NONBLOCK)
pio->fd_status_flags = O_NONBLOCK; pio->fd_status_flags = O_NONBLOCK;
pio->handle = handle; pio->handle = handle;
return pio; return pio;
} }
VOID CALLBACK ReadCompletionRoutine( VOID CALLBACK ReadCompletionRoutine(
_In_ DWORD dwErrorCode, _In_ DWORD dwErrorCode,
_In_ DWORD dwNumberOfBytesTransfered, _In_ DWORD dwNumberOfBytesTransfered,
_Inout_ LPOVERLAPPED lpOverlapped _Inout_ LPOVERLAPPED lpOverlapped
) { ) {
struct w32_io* pio = (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, read_overlapped)); struct w32_io* pio = (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, read_overlapped));
debug2("pio:%p, pending_state:%d, error:%d, transferred:%d", pio, pio->read_details.pending, dwErrorCode, dwNumberOfBytesTransfered); debug2("pio:%p, pending_state:%d, error:%d, transferred:%d", pio, pio->read_details.pending, dwErrorCode, dwNumberOfBytesTransfered);
pio->read_details.error = dwErrorCode; pio->read_details.error = dwErrorCode;
pio->read_details.remaining = dwNumberOfBytesTransfered; pio->read_details.remaining = dwNumberOfBytesTransfered;
pio->read_details.completed = 0; pio->read_details.completed = 0;
pio->read_details.pending = FALSE; pio->read_details.pending = FALSE;
} }
#define READ_BUFFER_SIZE 100*1024 #define READ_BUFFER_SIZE 100*1024
int fileio_ReadFileEx(struct w32_io* pio) { int
fileio_ReadFileEx(struct w32_io* pio) {
if (pio->read_details.buf == NULL) if (pio->read_details.buf == NULL)
{ {
pio->read_details.buf = malloc(READ_BUFFER_SIZE); pio->read_details.buf = malloc(READ_BUFFER_SIZE);
if (!pio->read_details.buf) if (!pio->read_details.buf)
{ {
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;
} }
pio->read_details.buf_size = READ_BUFFER_SIZE; pio->read_details.buf_size = READ_BUFFER_SIZE;
} }
if (ReadFileEx(pio->handle, pio->read_details.buf, pio->read_details.buf_size, &pio->read_overlapped, &ReadCompletionRoutine)) if (ReadFileEx(pio->handle, pio->read_details.buf, pio->read_details.buf_size, &pio->read_overlapped, &ReadCompletionRoutine))
{ {
pio->read_details.pending = TRUE; pio->read_details.pending = TRUE;
} }
else else
{ {
errno = errno_from_Win32LastError(); errno = errno_from_Win32LastError();
return -1; return -1;
} }
return 0; return 0;
} }
int fileio_read(struct w32_io* pio, void *dst, unsigned int max) { int
int bytes_copied; fileio_read(struct w32_io* pio, void *dst, unsigned int max) {
int bytes_copied;
if ((pio->type == PIPE_FD) && (pio->internal.state == PIPE_WRITE_END)) { if ((pio->type == PIPE_FD) && (pio->internal.state == PIPE_WRITE_END)) {
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
//if read is pending //if read is pending
if (pio->read_details.pending) { if (pio->read_details.pending) {
errno = EAGAIN; errno = EAGAIN;
debug2("IO is already pending"); debug2("IO is already pending");
return -1; return -1;
} }
if (fileio_is_io_available(pio, TRUE) == FALSE) if (fileio_is_io_available(pio, TRUE) == FALSE)
{ {
if (-1 == fileio_ReadFileEx(pio)) { if (-1 == fileio_ReadFileEx(pio)) {
if ((pio->type == PIPE_FD) && (errno == ERROR_NEGATIVE_SEEK)) {//write end of the pipe closed if ((pio->type == PIPE_FD) && (errno == ERROR_NEGATIVE_SEEK)) {//write end of the pipe closed
debug2("no more data"); debug2("no more data");
errno = 0; errno = 0;
return 0; return 0;
} }
return -1; return -1;
} }
//Pick up APC if IO has completed //Pick up APC if IO has completed
SleepEx(0, TRUE); SleepEx(0, TRUE);
if (w32_io_is_blocking(pio)) { if (w32_io_is_blocking(pio)) {
while (fileio_is_io_available(pio, TRUE) == FALSE) { while (fileio_is_io_available(pio, TRUE) == FALSE) {
if (-1 == wait_for_any_event(NULL, 0, INFINITE)) if (-1 == wait_for_any_event(NULL, 0, INFINITE))
return -1; return -1;
} }
} }
else if (pio->read_details.pending) { else if (pio->read_details.pending) {
errno = EAGAIN; errno = EAGAIN;
debug2("IO is pending"); debug2("IO is pending");
return -1; return -1;
} }
} }
if (pio->read_details.error) { if (pio->read_details.error) {
errno = errno_from_Win32Error(pio->read_details.error); errno = errno_from_Win32Error(pio->read_details.error);
if ((errno == ERROR_BROKEN_PIPE) || //write end of the pipe is closed or pipe broken if ((errno == ERROR_BROKEN_PIPE) || //write end of the pipe is closed or pipe broken
(errno == ERROR_HANDLE_EOF)) { //end of file reached (errno == ERROR_HANDLE_EOF)) { //end of file reached
debug2("no more data"); debug2("no more data");
errno = 0; errno = 0;
pio->read_details.error = 0; pio->read_details.error = 0;
return 0; return 0;
} }
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
pio->read_details.error = 0; pio->read_details.error = 0;
return -1; return -1;
} }
bytes_copied = min(max, pio->read_details.remaining); bytes_copied = min(max, pio->read_details.remaining);
memcpy(dst, pio->read_details.buf + pio->read_details.completed, bytes_copied); memcpy(dst, pio->read_details.buf + pio->read_details.completed, bytes_copied);
pio->read_details.remaining -= bytes_copied; pio->read_details.remaining -= bytes_copied;
pio->read_details.completed += bytes_copied; pio->read_details.completed += bytes_copied;
debug2("read %d bytes", bytes_copied); debug2("read %d bytes", bytes_copied);
return bytes_copied; return bytes_copied;
} }
VOID CALLBACK WriteCompletionRoutine( VOID CALLBACK WriteCompletionRoutine(
_In_ DWORD dwErrorCode, _In_ DWORD dwErrorCode,
_In_ DWORD dwNumberOfBytesTransfered, _In_ DWORD dwNumberOfBytesTransfered,
_Inout_ LPOVERLAPPED lpOverlapped _Inout_ LPOVERLAPPED lpOverlapped
) { ) {
struct w32_io* pio = (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, write_overlapped)); struct w32_io* pio = (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, write_overlapped));
debug2("pio:%p, pending_state:%d, remaining:%d, error:%d, transferred:%d", pio, pio->write_details.pending, pio->write_details.remaining, dwErrorCode, dwNumberOfBytesTransfered); debug2("pio:%p, pending_state:%d, remaining:%d, error:%d, transferred:%d", pio, pio->write_details.pending, pio->write_details.remaining, dwErrorCode, dwNumberOfBytesTransfered);
pio->write_details.error = dwErrorCode; pio->write_details.error = dwErrorCode;
//assert that remaining == dwNumberOfBytesTransfered //assert that remaining == dwNumberOfBytesTransfered
pio->write_details.remaining -= dwNumberOfBytesTransfered; pio->write_details.remaining -= dwNumberOfBytesTransfered;
pio->write_details.pending = FALSE; pio->write_details.pending = FALSE;
} }
#define WRITE_BUFFER_SIZE 100*1024 #define WRITE_BUFFER_SIZE 100*1024
int fileio_write(struct w32_io* pio, const void *buf, unsigned int max) { int
int bytes_copied; fileio_write(struct w32_io* pio, const void *buf, unsigned int max) {
int bytes_copied;
if ((pio->type == PIPE_FD) && (pio->internal.state == PIPE_READ_END)) { if ((pio->type == PIPE_FD) && (pio->internal.state == PIPE_READ_END)) {
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
if (pio->write_details.pending) { if (pio->write_details.pending) {
if (w32_io_is_blocking(pio)) if (w32_io_is_blocking(pio))
{ {
//this covers the scenario when the fd was previously non blocking (and hence io is still pending) //this covers the scenario when the fd was previously non blocking (and hence io is still pending)
//wait for previous io to complete //wait for previous io to complete
debug2("waiting for prior unblocking write to complete before proceeding with this blocking write"); debug2("waiting for prior unblocking write to complete before proceeding with this blocking write");
while (pio->write_details.pending) { while (pio->write_details.pending) {
if (wait_for_any_event(NULL, 0, INFINITE) == -1) if (wait_for_any_event(NULL, 0, INFINITE) == -1)
return -1; return -1;
} }
} }
else { else {
errno = EAGAIN; errno = EAGAIN;
debug2("IO is already pending"); debug2("IO is already pending");
return -1; return -1;
} }
} }
if (pio->write_details.error) { if (pio->write_details.error) {
errno = errno_from_Win32Error(pio->write_details.error); errno = errno_from_Win32Error(pio->write_details.error);
debug("ERROR:%d on prior unblocking write", errno); debug("ERROR:%d on prior unblocking write", errno);
pio->write_details.error = 0; pio->write_details.error = 0;
return -1; return -1;
} }
if (pio->write_details.buf == NULL) { if (pio->write_details.buf == NULL) {
pio->write_details.buf = malloc(WRITE_BUFFER_SIZE); pio->write_details.buf = malloc(WRITE_BUFFER_SIZE);
if (pio->write_details.buf == NULL) { if (pio->write_details.buf == NULL) {
errno = ENOMEM; errno = ENOMEM;
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
return -1; return -1;
} }
pio->write_details.buf_size = WRITE_BUFFER_SIZE; pio->write_details.buf_size = WRITE_BUFFER_SIZE;
} }
bytes_copied = min(max, pio->write_details.buf_size); bytes_copied = min(max, pio->write_details.buf_size);
memcpy(pio->write_details.buf, buf, bytes_copied); memcpy(pio->write_details.buf, buf, bytes_copied);
if (WriteFileEx(pio->handle, pio->write_details.buf, bytes_copied, &pio->write_overlapped, &WriteCompletionRoutine)) if (WriteFileEx(pio->handle, pio->write_details.buf, bytes_copied, &pio->write_overlapped, &WriteCompletionRoutine))
{ {
pio->write_details.pending = TRUE; pio->write_details.pending = TRUE;
//let APC execute if IO was complete //let APC execute if IO was complete
SleepEx(0, TRUE); SleepEx(0, TRUE);
if (w32_io_is_blocking(pio)) { if (w32_io_is_blocking(pio)) {
while (pio->write_details.pending) { while (pio->write_details.pending) {
if (wait_for_any_event(NULL, 0, INFINITE) == -1) if (wait_for_any_event(NULL, 0, INFINITE) == -1)
return -1; return -1;
} }
} }
if (!pio->write_details.pending && pio->write_details.error){ if (!pio->write_details.pending && pio->write_details.error) {
errno = errno_from_Win32Error(pio->write_details.error); errno = errno_from_Win32Error(pio->write_details.error);
pio->write_details.error = 0; pio->write_details.error = 0;
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
return -1; return -1;
} }
return bytes_copied; return bytes_copied;
} }
else else
{ {
errno = errno_from_Win32LastError(); errno = errno_from_Win32LastError();
if ((pio->type == PIPE_FD) && (errno == ERROR_NEGATIVE_SEEK)) {//read end of the pipe closed if ((pio->type == PIPE_FD) && (errno == ERROR_NEGATIVE_SEEK)) {//read end of the pipe closed
debug("ERROR:read end of the pipe closed"); debug("ERROR:read end of the pipe closed");
errno = EPIPE; errno = EPIPE;
} }
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
return -1; return -1;
} }
} }
int fileio_fstat(struct w32_io* pio, struct stat *buf) { int
fileio_fstat(struct w32_io* pio, struct stat *buf) {
errno = ENOTSUP; errno = ENOTSUP;
return -1; return -1;
int fd = _open_osfhandle((intptr_t)pio->handle, 0); int fd = _open_osfhandle((intptr_t)pio->handle, 0);
debug2("pio:%p", pio); debug2("pio:%p", pio);
if (fd == -1) { if (fd == -1) {
errno = EOTHER; errno = EOTHER;
return -1; return -1;
} }
return _fstat(fd, (struct _stat*)&buf); return _fstat(fd, (struct _stat*)&buf);
} }
int fileio_isatty(struct w32_io* pio) { int
return (GetFileType(pio->handle) == FILE_TYPE_CHAR) ? TRUE : FALSE; fileio_isatty(struct w32_io* pio) {
return (GetFileType(pio->handle) == FILE_TYPE_CHAR) ? TRUE : FALSE;
} }
FILE* fileio_fdopen(struct w32_io* pio, const char *mode) { FILE*
fileio_fdopen(struct w32_io* pio, const char *mode) {
int fd_flags = 0; int fd_flags = 0;
debug2("pio:%p", pio); debug2("pio:%p", pio);
if (mode[1] == '\0') { if (mode[1] == '\0') {
switch (*mode) { switch (*mode) {
case 'r': case 'r':
fd_flags = _O_RDONLY; fd_flags = _O_RDONLY;
break; break;
case 'w': case 'w':
break; break;
case 'a': case 'a':
fd_flags = _O_APPEND; fd_flags = _O_APPEND;
break; break;
default: default:
errno = ENOTSUP; errno = ENOTSUP;
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
return NULL; return NULL;
} }
} }
else { else {
errno = ENOTSUP; errno = ENOTSUP;
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
return NULL; return NULL;
} }
int fd = _open_osfhandle((intptr_t)pio->handle, fd_flags); int fd = _open_osfhandle((intptr_t)pio->handle, fd_flags);
if (fd == -1) { if (fd == -1) {
errno = EOTHER; errno = EOTHER;
debug("ERROR:%d", errno); debug("ERROR:%d", errno);
return NULL; return NULL;
} }
return _fdopen(fd, mode); return _fdopen(fd, mode);
} }
int fileio_on_select(struct w32_io* pio, BOOL rd) { int
fileio_on_select(struct w32_io* pio, BOOL rd) {
if (!rd) if (!rd)
return 0; return 0;
if (!pio->read_details.pending && !fileio_is_io_available(pio, rd)) if (!pio->read_details.pending && !fileio_is_io_available(pio, rd))
return fileio_ReadFileEx(pio); return fileio_ReadFileEx(pio);
return 0; return 0;
} }
int fileio_close(struct w32_io* pio) { int
debug2("pio:%p", pio); fileio_close(struct w32_io* pio) {
CancelIo(pio->handle); debug2("pio:%p", pio);
//let queued APCs (if any) drain CancelIo(pio->handle);
SleepEx(0, TRUE); //let queued APCs (if any) drain
if (pio->type != STD_IO_FD) //STD handles are never explicitly closed SleepEx(0, TRUE);
CloseHandle(pio->handle); if (pio->type != STD_IO_FD) //STD handles are never explicitly closed
CloseHandle(pio->handle);
if (pio->read_details.buf) if (pio->read_details.buf)
free(pio->read_details.buf); free(pio->read_details.buf);
if (pio->write_details.buf) if (pio->write_details.buf)
free(pio->write_details.buf); free(pio->write_details.buf);
free(pio); free(pio);
return 0; return 0;
} }
BOOL fileio_is_io_available(struct w32_io* pio, BOOL rd) { BOOL
if (rd){ fileio_is_io_available(struct w32_io* pio, BOOL rd) {
if (pio->read_details.remaining || pio->read_details.error) if (rd) {
return TRUE; if (pio->read_details.remaining || pio->read_details.error)
else return TRUE;
return FALSE; else
} return FALSE;
else { //write }
return (pio->write_details.pending == FALSE) ? TRUE : FALSE; else { //write
} return (pio->write_details.pending == FALSE) ? TRUE : FALSE;
}
} }

View File

@ -16,49 +16,50 @@
// - time out (errno = ETIMEOUT) // - time out (errno = ETIMEOUT)
// Returns 0 on IO completion and -1 on rest // Returns 0 on IO completion and -1 on rest
// if milli_seconds is 0, this function returns 0, its called with 0 to execute any scheduled APCs // if milli_seconds is 0, this function returns 0, its called with 0 to execute any scheduled APCs
int wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds) int
wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds)
{ {
//todo - implement signal catching and handling //todo - implement signal catching and handling
if (num_events) if (num_events)
{ {
DWORD ret = WaitForMultipleObjectsEx(num_events, events, FALSE, milli_seconds, TRUE); DWORD ret = WaitForMultipleObjectsEx(num_events, events, FALSE, milli_seconds, TRUE);
if ((ret >= WAIT_OBJECT_0) && (ret <= WAIT_OBJECT_0 + num_events - 1)) { if ((ret >= WAIT_OBJECT_0) && (ret <= WAIT_OBJECT_0 + num_events - 1)) {
//woken up by event signalled //woken up by event signalled
return 0; return 0;
} }
else if (ret == WAIT_IO_COMPLETION) { else if (ret == WAIT_IO_COMPLETION) {
return 0; return 0;
} }
else if (ret == WAIT_TIMEOUT) { else if (ret == WAIT_TIMEOUT) {
if (milli_seconds == 0) if (milli_seconds == 0)
return 0; return 0;
errno = ETIMEDOUT; errno = ETIMEDOUT;
debug("ERROR: wait timed out"); debug("ERROR: wait timed out");
return -1; return -1;
} }
else { //some other error else { //some other error
errno = EOTHER; errno = EOTHER;
debug("ERROR: unxpected wait end with error: %d", ret); debug("ERROR: unxpected wait end with error: %d", ret);
return -1; return -1;
} }
} }
else else
{ {
DWORD ret = SleepEx(milli_seconds, TRUE); DWORD ret = SleepEx(milli_seconds, TRUE);
if (ret == WAIT_IO_COMPLETION) { if (ret == WAIT_IO_COMPLETION) {
return 0; return 0;
} }
else if (ret == 0) { else if (ret == 0) {
if (milli_seconds == 0) if (milli_seconds == 0)
return 0; return 0;
errno = ETIMEDOUT; errno = ETIMEDOUT;
debug("ERROR: wait timed out"); debug("ERROR: wait timed out");
return -1; return -1;
} }
else { //some other error else { //some other error
errno = EOTHER; errno = EOTHER;
debug("ERROR: unxpected SleepEx error: %d", ret); debug("ERROR: unxpected SleepEx error: %d", ret);
return -1; return -1;
} }
} }
} }

View File

@ -52,7 +52,7 @@ fd_table_get_min_index() {
unsigned char* bitmap = fd_table.occupied.bitmap; unsigned char* bitmap = fd_table.occupied.bitmap;
unsigned char tmp; unsigned char tmp;
while (*bitmap == 0xff) { while (*bitmap == 0xff) {
bitmap++; bitmap++;
min_index += 8; min_index += 8;
if (min_index >= MAX_FDS) { if (min_index >= MAX_FDS) {
@ -66,8 +66,8 @@ fd_table_get_min_index() {
while (tmp & 0x80) while (tmp & 0x80)
{ {
tmp <<= 1; tmp <<= 1;
min_index++; min_index++;
} }
return min_index; return min_index;
@ -92,8 +92,8 @@ fd_table_clear(int index)
void void
w32posix_initialize() { w32posix_initialize() {
if ((debug_initialize() != 0) if ((debug_initialize() != 0)
|| (fd_table_initialize() != 0) || (fd_table_initialize() != 0)
|| (socketio_initialize() != 0)) || (socketio_initialize() != 0))
abort(); abort();
} }
@ -267,7 +267,7 @@ w32_shutdown(int fd, int how) {
int int
w32_pipe(int *pfds){ w32_pipe(int *pfds) {
int read_index, write_index; int read_index, write_index;
struct w32_io* pio[2]; struct w32_io* pio[2];
@ -377,7 +377,7 @@ w32_fcntl(int fd, int cmd, ... /* arg */) {
CHECK_FD(fd); CHECK_FD(fd);
switch (cmd){ switch (cmd) {
case F_GETFL: case F_GETFL:
return fd_table.w32_ios[fd]->fd_status_flags; return fd_table.w32_ios[fd]->fd_status_flags;
case F_SETFL: case F_SETFL:
@ -393,7 +393,7 @@ w32_fcntl(int fd, int cmd, ... /* arg */) {
errno = EINVAL; errno = EINVAL;
debug("ERROR: cmd:%d", cmd); debug("ERROR: cmd:%d", cmd);
return -1; return -1;
} }
} }
int int
@ -409,7 +409,7 @@ w32_select(int fds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const
memset(&read_ready_fds, 0, sizeof(fd_set)); memset(&read_ready_fds, 0, sizeof(fd_set));
memset(&write_ready_fds, 0, sizeof(fd_set)); memset(&write_ready_fds, 0, sizeof(fd_set));
if (fds > MAX_FDS ) { if (fds > MAX_FDS) {
errno = EINVAL; errno = EINVAL;
debug("ERROR: fds: %d", fds); debug("ERROR: fds: %d", fds);
return -1; return -1;
@ -487,8 +487,8 @@ w32_select(int fds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const
if (writefds && FD_ISSET(i, writefds)) { if (writefds && FD_ISSET(i, writefds)) {
if (w32_io_is_io_available(fd_table.w32_ios[i], FALSE)) { if (w32_io_is_io_available(fd_table.w32_ios[i], FALSE)) {
FD_SET(i, &write_ready_fds); FD_SET(i, &write_ready_fds);
out_ready_fds++; out_ready_fds++;
} }
} }
} }