mirror of
https://github.com/PowerShell/Win32-OpenSSH.git
synced 2025-09-21 17:18:40 +02:00
Term IO implemented to support Vista and Win7
This commit is contained in:
parent
fb93bb95e2
commit
a8fcb8d673
@ -43,6 +43,9 @@
|
||||
#define WRITE_BUFFER_SIZE 100*1024
|
||||
#define errno_from_Win32LastError() errno_from_Win32Error(GetLastError())
|
||||
|
||||
int termio_initiate_read(struct w32_io* pio);
|
||||
int termio_initiate_write(struct w32_io* pio, DWORD num_bytes);
|
||||
|
||||
/* maps Win32 error to errno */
|
||||
int
|
||||
errno_from_Win32Error(int win32_error)
|
||||
@ -182,7 +185,7 @@ createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags) {
|
||||
|
||||
/*only following create and status flags currently supported*/
|
||||
if (c_s_flags & ~(O_NONBLOCK | O_APPEND | O_CREAT | O_TRUNC
|
||||
| O_EXCL | O_BINARY)) {
|
||||
| O_EXCL | O_BINARY)) {
|
||||
debug("open - ERROR: Unsupported flags: %d", flags);
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
@ -235,7 +238,7 @@ createFile_flags_setup(int flags, int mode, struct createFile_flags* cf_flags) {
|
||||
|
||||
/* open() implementation. Uses CreateFile to open file, console, device, etc */
|
||||
struct w32_io*
|
||||
fileio_open(const char *pathname, int flags, int mode) {
|
||||
fileio_open(const char *pathname, int flags, int mode) {
|
||||
struct w32_io* pio = NULL;
|
||||
struct createFile_flags cf_flags;
|
||||
HANDLE handle;
|
||||
@ -254,8 +257,8 @@ fileio_open(const char *pathname, int flags, int mode) {
|
||||
|
||||
/* TODO - Use unicode version.*/
|
||||
handle = CreateFileA(pathname, cf_flags.dwDesiredAccess, cf_flags.dwShareMode,
|
||||
&cf_flags.securityAttributes, cf_flags.dwCreationDisposition,
|
||||
cf_flags.dwFlagsAndAttributes, NULL);
|
||||
&cf_flags.securityAttributes, cf_flags.dwCreationDisposition,
|
||||
cf_flags.dwFlagsAndAttributes, NULL);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
errno = errno_from_Win32LastError();
|
||||
@ -280,12 +283,12 @@ fileio_open(const char *pathname, int flags, int mode) {
|
||||
}
|
||||
|
||||
VOID CALLBACK ReadCompletionRoutine(
|
||||
_In_ DWORD dwErrorCode,
|
||||
_In_ DWORD dwNumberOfBytesTransfered,
|
||||
_Inout_ LPOVERLAPPED lpOverlapped
|
||||
_In_ DWORD dwErrorCode,
|
||||
_In_ DWORD dwNumberOfBytesTransfered,
|
||||
_Inout_ LPOVERLAPPED lpOverlapped
|
||||
) {
|
||||
struct w32_io* pio =
|
||||
(struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, read_overlapped));
|
||||
(struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, read_overlapped));
|
||||
debug2("ReadCB pio:%p, pending_state:%d, error:%d, received:%d",
|
||||
pio, pio->read_details.pending, dwErrorCode, dwNumberOfBytesTransfered);
|
||||
pio->read_details.error = dwErrorCode;
|
||||
@ -300,7 +303,7 @@ int
|
||||
fileio_ReadFileEx(struct w32_io* pio) {
|
||||
debug2("ReadFileEx io:%p", pio);
|
||||
|
||||
if (pio->read_details.buf == NULL){
|
||||
if (pio->read_details.buf == NULL) {
|
||||
pio->read_details.buf = malloc(READ_BUFFER_SIZE);
|
||||
if (!pio->read_details.buf) {
|
||||
errno = ENOMEM;
|
||||
@ -311,7 +314,7 @@ fileio_ReadFileEx(struct w32_io* pio) {
|
||||
}
|
||||
|
||||
if (ReadFileEx(WINHANDLE(pio), pio->read_details.buf, pio->read_details.buf_size,
|
||||
&pio->read_overlapped, &ReadCompletionRoutine))
|
||||
&pio->read_overlapped, &ReadCompletionRoutine))
|
||||
pio->read_details.pending = TRUE;
|
||||
else {
|
||||
errno = errno_from_Win32LastError();
|
||||
@ -344,15 +347,21 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) {
|
||||
}
|
||||
|
||||
if (fileio_is_io_available(pio, TRUE) == FALSE) {
|
||||
if (-1 == fileio_ReadFileEx(pio)) {
|
||||
if ((FILETYPE(pio) == FILE_TYPE_PIPE)
|
||||
&& (errno == ERROR_NEGATIVE_SEEK)) {
|
||||
/* write end of the pipe closed */
|
||||
debug2("read - no more data, io:%p", pio);
|
||||
errno = 0;
|
||||
return 0;
|
||||
if (FILETYPE(pio) == FILE_TYPE_CHAR) {
|
||||
if (-1 == termio_initiate_read(pio))
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
if (-1 == fileio_ReadFileEx(pio)) {
|
||||
if ((FILETYPE(pio) == FILE_TYPE_PIPE)
|
||||
&& (errno == ERROR_NEGATIVE_SEEK)) {
|
||||
/* write end of the pipe closed */
|
||||
debug2("read - no more data, io:%p", pio);
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* pick up APC if IO has completed */
|
||||
@ -392,7 +401,7 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) {
|
||||
pio->read_details.remaining -= bytes_copied;
|
||||
pio->read_details.completed += bytes_copied;
|
||||
debug2("read - io:%p read: %d remaining: %d", pio, bytes_copied,
|
||||
pio->read_details.remaining);
|
||||
pio->read_details.remaining);
|
||||
return bytes_copied;
|
||||
}
|
||||
|
||||
@ -402,10 +411,10 @@ VOID CALLBACK WriteCompletionRoutine(
|
||||
_Inout_ LPOVERLAPPED lpOverlapped
|
||||
) {
|
||||
struct w32_io* pio =
|
||||
(struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, write_overlapped));
|
||||
(struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, write_overlapped));
|
||||
debug2("WriteCB - pio:%p, pending_state:%d, error:%d, transferred:%d of remaining: %d",
|
||||
pio, pio->write_details.pending, dwErrorCode, dwNumberOfBytesTransfered,
|
||||
pio->write_details.remaining);
|
||||
pio, pio->write_details.pending, dwErrorCode, dwNumberOfBytesTransfered,
|
||||
pio->write_details.remaining);
|
||||
pio->write_details.error = dwErrorCode;
|
||||
/* TODO - assert that remaining == dwNumberOfBytesTransfered */
|
||||
if ((dwErrorCode == 0) && (pio->write_details.remaining != dwNumberOfBytesTransfered)) {
|
||||
@ -461,39 +470,49 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) {
|
||||
bytes_copied = min(max, pio->write_details.buf_size);
|
||||
memcpy(pio->write_details.buf, buf, bytes_copied);
|
||||
|
||||
if (WriteFileEx(WINHANDLE(pio), pio->write_details.buf, bytes_copied,
|
||||
&pio->write_overlapped, &WriteCompletionRoutine)) {
|
||||
pio->write_details.pending = TRUE;
|
||||
pio->write_details.remaining = bytes_copied;
|
||||
/* execute APC if write has completed */
|
||||
if (wait_for_any_event(NULL, 0, 0) == -1)
|
||||
return -1;
|
||||
|
||||
if (w32_io_is_blocking(pio)) {
|
||||
while (pio->write_details.pending) {
|
||||
if (wait_for_any_event(NULL, 0, INFINITE) == -1)
|
||||
return -1;
|
||||
}
|
||||
if (FILETYPE(pio) == FILE_TYPE_CHAR) {
|
||||
if (termio_initiate_write(pio, bytes_copied) == 0) {
|
||||
pio->write_details.pending = TRUE;
|
||||
pio->write_details.remaining = bytes_copied;
|
||||
}
|
||||
if (!pio->write_details.pending && pio->write_details.error) {
|
||||
errno = errno_from_Win32Error(pio->write_details.error);
|
||||
debug("write - ERROR from cb:%d, io:%p", pio->write_details.error, pio);
|
||||
pio->write_details.error = 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
debug2("write - reporting %d bytes written, io:%p", bytes_copied, pio);
|
||||
return bytes_copied;
|
||||
}
|
||||
else {
|
||||
errno = errno_from_Win32LastError();
|
||||
/* read end of the pipe closed ? */
|
||||
if ((FILETYPE(pio) == FILE_TYPE_PIPE) && (errno == ERROR_NEGATIVE_SEEK)) {
|
||||
debug("write - ERROR:read end of the pipe closed, io:%p", pio);
|
||||
errno = EPIPE;
|
||||
if (WriteFileEx(WINHANDLE(pio), pio->write_details.buf, bytes_copied,
|
||||
&pio->write_overlapped, &WriteCompletionRoutine)) {
|
||||
pio->write_details.pending = TRUE;
|
||||
pio->write_details.remaining = bytes_copied;
|
||||
/* execute APC if write has completed */
|
||||
if (wait_for_any_event(NULL, 0, 0) == -1)
|
||||
return -1;
|
||||
}
|
||||
debug("write ERROR from cb(2):%d, io:%p", errno, pio);
|
||||
else {
|
||||
errno = errno_from_Win32LastError();
|
||||
/* read end of the pipe closed ? */
|
||||
if ((FILETYPE(pio) == FILE_TYPE_PIPE) && (errno == ERROR_NEGATIVE_SEEK)) {
|
||||
debug("write - ERROR:read end of the pipe closed, io:%p", pio);
|
||||
errno = EPIPE;
|
||||
}
|
||||
debug("write ERROR from cb(2):%d, io:%p", errno, pio);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (w32_io_is_blocking(pio)) {
|
||||
while (pio->write_details.pending) {
|
||||
if (wait_for_any_event(NULL, 0, INFINITE) == -1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (!pio->write_details.pending && pio->write_details.error) {
|
||||
errno = errno_from_Win32Error(pio->write_details.error);
|
||||
debug("write - ERROR from cb:%d, io:%p", pio->write_details.error, pio);
|
||||
pio->write_details.error = 0;
|
||||
return -1;
|
||||
}
|
||||
debug2("write - reporting %d bytes written, io:%p", bytes_copied, pio);
|
||||
return bytes_copied;
|
||||
|
||||
}
|
||||
|
||||
@ -577,7 +596,10 @@ fileio_on_select(struct w32_io* pio, BOOL rd) {
|
||||
return 0;
|
||||
|
||||
if (!pio->read_details.pending && !fileio_is_io_available(pio, rd))
|
||||
return fileio_ReadFileEx(pio);
|
||||
if (FILETYPE(pio) == FILE_TYPE_CHAR)
|
||||
return termio_initiate_read(pio);
|
||||
else
|
||||
return fileio_ReadFileEx(pio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3,10 +3,9 @@
|
||||
#include "inc/defs.h"
|
||||
|
||||
#define TERM_IO_BUF_SIZE 2048
|
||||
int errno_from_Win32Error(int win32_error);
|
||||
|
||||
struct io_status {
|
||||
char* buf[TERM_IO_BUF_SIZE];
|
||||
DWORD to_transfer;
|
||||
DWORD transferred;
|
||||
DWORD error;
|
||||
};
|
||||
@ -17,79 +16,137 @@ static VOID CALLBACK ReadAPCProc(
|
||||
_In_ ULONG_PTR dwParam
|
||||
) {
|
||||
struct w32_io* pio = (struct w32_io*)dwParam;
|
||||
debug3("TermRead CB - io:%p, bytes: %d, pending: %d, error: %d", pio, read_status.transferred,
|
||||
pio->read_details.pending, read_status.error);
|
||||
pio->read_details.error = read_status.error;
|
||||
pio->read_details.remaining = read_status.transferred;
|
||||
pio->read_details.completed = 0;
|
||||
pio->read_details.pending = FALSE;
|
||||
WaitForSingleObject(pio->read_overlapped.hEvent, INFINITE);
|
||||
CloseHandle(pio->read_overlapped.hEvent);
|
||||
pio->read_overlapped.hEvent = 0;
|
||||
}
|
||||
|
||||
static DWORD WINAPI ReadThread(
|
||||
_In_ LPVOID lpParameter
|
||||
) {
|
||||
struct w32_io* pio = (struct w32_io*)lpParameter;
|
||||
debug3("TermRead thread, io:%p", pio);
|
||||
memset(&read_status, 0, sizeof(read_status));
|
||||
if (!ReadFile(WINHANDLE(pio), read_status.buf, TERM_IO_BUF_SIZE, &read_status.transferred, NULL)) {
|
||||
if (!ReadFile(WINHANDLE(pio), pio->read_details.buf,
|
||||
pio->read_details.buf_size, &read_status.transferred, NULL)) {
|
||||
read_status.error = GetLastError();
|
||||
debug("TermRead thread - ReadFile failed %d, io:%p", GetLastError(), pio);
|
||||
}
|
||||
|
||||
if (0 == QueueUserAPC(ReadAPCProc, main_thread, pio))
|
||||
if (0 == QueueUserAPC(ReadAPCProc, main_thread, (ULONG_PTR)pio)) {
|
||||
debug("TermRead thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio);
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
static int
|
||||
termio_initiate_read(struct w32_io* pio) {
|
||||
HANDLE read_thread = CreateThread(NULL, 0, ReadThread, pio, 0, NULL);
|
||||
if (read_thread == NULL) {
|
||||
errno = errno_from_Win32Error(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
termio_on_select(struct w32_io* pio, BOOL rd) {
|
||||
if (!rd)
|
||||
return 0;
|
||||
termio_initiate_read(struct w32_io* pio) {
|
||||
HANDLE read_thread;
|
||||
|
||||
if ((!fileio_is_io_available(pio, rd)) && (!pio->read_details.pending))
|
||||
return termio_initiate_read(pio);
|
||||
debug3("TermRead initiate io:%p", pio);
|
||||
|
||||
if (pio->read_details.buf_size == 0) {
|
||||
pio->read_details.buf = malloc(TERM_IO_BUF_SIZE);
|
||||
if (pio->read_details.buf == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
pio->read_details.buf_size = TERM_IO_BUF_SIZE;
|
||||
}
|
||||
|
||||
read_thread = CreateThread(NULL, 0, ReadThread, pio, 0, NULL);
|
||||
if (read_thread == NULL) {
|
||||
errno = errno_from_Win32Error(GetLastError());
|
||||
debug("TermRead initiate - ERROR CreateThread %d, io:%p", GetLastError(), pio);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pio->read_overlapped.hEvent = read_thread;
|
||||
pio->read_details.pending = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VOID CALLBACK WriteAPCProc(
|
||||
_In_ ULONG_PTR dwParam
|
||||
) {
|
||||
struct w32_io* pio = (struct w32_io*)dwParam;
|
||||
debug3("TermWrite CB - io:%p, bytes: %d, pending: %d, error: %d", pio, write_status.transferred,
|
||||
pio->write_details.pending, write_status.error);
|
||||
pio->write_details.error = write_status.error;
|
||||
pio->write_details.remaining -= write_status.transferred;
|
||||
/*TODO- assert that reamining is 0 by now*/
|
||||
pio->write_details.completed = 0;
|
||||
pio->write_details.pending = FALSE;
|
||||
WaitForSingleObject(pio->write_overlapped.hEvent, INFINITE);
|
||||
CloseHandle(pio->write_overlapped.hEvent);
|
||||
pio->write_overlapped.hEvent = 0;
|
||||
}
|
||||
|
||||
static DWORD WINAPI WriteThread(
|
||||
_In_ LPVOID lpParameter
|
||||
) {
|
||||
struct w32_io* pio = (struct w32_io*)lpParameter;
|
||||
debug3("TermWrite thread, io:%p", pio);
|
||||
if (!WriteFile(WINHANDLE(pio), pio->write_details.buf, write_status.to_transfer,
|
||||
&write_status.transferred, NULL)) {
|
||||
write_status.error = GetLastError();
|
||||
debug("TermWrite thread - ReadFile failed %d, io:%p", GetLastError(), pio);
|
||||
}
|
||||
|
||||
if (0 == QueueUserAPC(WriteAPCProc, main_thread, (ULONG_PTR)pio)) {
|
||||
debug("TermWrite thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio);
|
||||
DebugBreak();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
termio_read(struct w32_io* pio, void *dst, unsigned int max) {
|
||||
return fileio_read(pio, dst, max);
|
||||
termio_initiate_write(struct w32_io* pio, DWORD num_bytes) {
|
||||
HANDLE write_thread;
|
||||
|
||||
debug3("TermWrite initiate io:%p", pio);
|
||||
memset(&write_status, 0, sizeof(write_status));
|
||||
write_status.to_transfer = num_bytes;
|
||||
write_thread = CreateThread(NULL, 0, WriteThread, pio, 0, NULL);
|
||||
if (write_thread == NULL) {
|
||||
errno = errno_from_Win32Error(GetLastError());
|
||||
debug("TermWrite initiate - ERROR CreateThread %d, io:%p", GetLastError(), pio);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pio->write_overlapped.hEvent = write_thread;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
termio_write(struct w32_io* pio, const void *buf, unsigned int max) {
|
||||
//{
|
||||
// /* assert that io is in blocking mode */
|
||||
// if (w32_io_is_blocking(pio) == FALSE) {
|
||||
// debug("write - ERROR, nonblocking write to term is not supported");
|
||||
// errno = ENOTSUP;
|
||||
// return -1;
|
||||
// }
|
||||
// pio->write_details.remaining = bytes_copied;
|
||||
// if (!WriteFile(h, buf, bytes_copied, &pio->write_details.completed, NULL))
|
||||
// pio->write_details.error = GetLastError();
|
||||
// else if (bytes_copied != pio->write_details.completed)
|
||||
// pio->write_details.error = ERROR_INTERNAL_ERROR;
|
||||
|
||||
// if (pio->write_details.error != 0) {
|
||||
// debug("write - ERROR writing to term %d", pio->write_details.error);
|
||||
// errno = errno_from_Win32Error(pio->write_details.error);
|
||||
// return -1;
|
||||
// }
|
||||
// else {
|
||||
// pio->write_details.completed = 0;
|
||||
// return bytes_copied;
|
||||
// }
|
||||
|
||||
//}
|
||||
return fileio_write(pio, buf, max);
|
||||
}
|
||||
|
||||
int termio_close(struct w32_io* pio) {
|
||||
return fileio_close(pio);
|
||||
debug2("termio_close - pio:%p", pio);
|
||||
|
||||
CancelIoEx(WINHANDLE(pio), NULL);
|
||||
/* If io is pending, let worker threads exit*/
|
||||
if (pio->read_details.pending)
|
||||
WaitForSingleObject(pio->read_overlapped.hEvent, INFINITE);
|
||||
if (pio->write_details.pending)
|
||||
WaitForSingleObject(pio->write_overlapped.hEvent, INFINITE);
|
||||
/* drain queued APCs */
|
||||
SleepEx(0, TRUE);
|
||||
if (pio->type != STD_IO_FD) {//STD handles are never explicitly closed
|
||||
CloseHandle(WINHANDLE(pio));
|
||||
|
||||
if (pio->read_details.buf)
|
||||
free(pio->read_details.buf);
|
||||
|
||||
if (pio->write_details.buf)
|
||||
free(pio->write_details.buf);
|
||||
|
||||
free(pio);
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -123,7 +123,7 @@ w32posix_initialize() {
|
||||
if ((fd_table_initialize() != 0)
|
||||
|| (socketio_initialize() != 0))
|
||||
DebugBreak();
|
||||
main_thread = GetCurrentThread();
|
||||
main_thread = OpenThread(THREAD_SET_CONTEXT, FALSE, GetCurrentThreadId());
|
||||
signalio_initialize();
|
||||
}
|
||||
|
||||
@ -156,13 +156,8 @@ w32_io_on_select(struct w32_io* pio, BOOL rd)
|
||||
{
|
||||
if ((pio->type == SOCK_FD))
|
||||
return socketio_on_select(pio, rd);
|
||||
else
|
||||
switch (FILETYPE(pio)) {
|
||||
case FILE_TYPE_CHAR:
|
||||
return termio_on_select(pio, rd);
|
||||
default:
|
||||
return fileio_on_select(pio, rd);
|
||||
}
|
||||
|
||||
return fileio_on_select(pio, rd);
|
||||
}
|
||||
|
||||
#define CHECK_FD(fd) do { \
|
||||
@ -371,13 +366,8 @@ w32_read(int fd, void *dst, unsigned int max) {
|
||||
|
||||
if (fd_table.w32_ios[fd]->type == SOCK_FD)
|
||||
return socketio_recv(fd_table.w32_ios[fd], dst, max, 0);
|
||||
else
|
||||
switch (FILETYPE(fd_table.w32_ios[fd])) {
|
||||
case FILE_TYPE_CHAR:
|
||||
return termio_read(fd_table.w32_ios[fd], dst, max);
|
||||
default:
|
||||
return fileio_read(fd_table.w32_ios[fd], dst, max);
|
||||
}
|
||||
|
||||
return fileio_read(fd_table.w32_ios[fd], dst, max);
|
||||
}
|
||||
|
||||
int
|
||||
@ -386,13 +376,8 @@ w32_write(int fd, const void *buf, unsigned int max) {
|
||||
|
||||
if (fd_table.w32_ios[fd]->type == SOCK_FD)
|
||||
return socketio_send(fd_table.w32_ios[fd], buf, max, 0);
|
||||
else
|
||||
switch (FILETYPE(fd_table.w32_ios[fd])) {
|
||||
case FILE_TYPE_CHAR:
|
||||
return termio_write(fd_table.w32_ios[fd], buf, max);
|
||||
default:
|
||||
return fileio_write(fd_table.w32_ios[fd], buf, max);
|
||||
}
|
||||
|
||||
return fileio_write(fd_table.w32_ios[fd], buf, max);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -119,9 +119,6 @@ long fileio_lseek(struct w32_io* pio, long offset, int origin);
|
||||
FILE* fileio_fdopen(struct w32_io* pio, const char *mode);
|
||||
|
||||
/* terminal io specific versions */
|
||||
int termio_on_select(struct w32_io* pio, BOOL rd);
|
||||
int termio_read(struct w32_io* pio, void *dst, unsigned int max);
|
||||
int termio_write(struct w32_io* pio, const void *buf, unsigned int max);
|
||||
int termio_close(struct w32_io* pio);
|
||||
|
||||
/* signal related APIs*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user