diff options
Diffstat (limited to 'winpr/libwinpr/io')
-rw-r--r-- | winpr/libwinpr/io/CMakeLists.txt | 22 | ||||
-rw-r--r-- | winpr/libwinpr/io/ModuleOptions.cmake | 9 | ||||
-rw-r--r-- | winpr/libwinpr/io/device.c | 234 | ||||
-rw-r--r-- | winpr/libwinpr/io/io.c | 276 | ||||
-rw-r--r-- | winpr/libwinpr/io/io.h | 37 | ||||
-rw-r--r-- | winpr/libwinpr/io/test/CMakeLists.txt | 25 | ||||
-rw-r--r-- | winpr/libwinpr/io/test/TestIoGetOverlappedResult.c | 10 |
7 files changed, 613 insertions, 0 deletions
diff --git a/winpr/libwinpr/io/CMakeLists.txt b/winpr/libwinpr/io/CMakeLists.txt new file mode 100644 index 0000000..c7050d4 --- /dev/null +++ b/winpr/libwinpr/io/CMakeLists.txt @@ -0,0 +1,22 @@ +# WinPR: Windows Portable Runtime +# libwinpr-io cmake build script +# +# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +winpr_module_add(device.c io.c io.h) + +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/winpr/libwinpr/io/ModuleOptions.cmake b/winpr/libwinpr/io/ModuleOptions.cmake new file mode 100644 index 0000000..f9f991d --- /dev/null +++ b/winpr/libwinpr/io/ModuleOptions.cmake @@ -0,0 +1,9 @@ + +set(MINWIN_LAYER "1") +set(MINWIN_GROUP "core") +set(MINWIN_MAJOR_VERSION "1") +set(MINWIN_MINOR_VERSION "1") +set(MINWIN_SHORT_NAME "io") +set(MINWIN_LONG_NAME "Asynchronous I/O Functions") +set(MODULE_LIBRARY_NAME "api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}") + diff --git a/winpr/libwinpr/io/device.c b/winpr/libwinpr/io/device.c new file mode 100644 index 0000000..0643acd --- /dev/null +++ b/winpr/libwinpr/io/device.c @@ -0,0 +1,234 @@ +/** + * WinPR: Windows Portable Runtime + * Asynchronous I/O Functions + * + * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <winpr/config.h> + +#include <winpr/io.h> + +#ifndef _WIN32 + +#include "io.h" + +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> + +#ifdef WINPR_HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> + +#include <winpr/crt.h> +#include <winpr/path.h> +#include <winpr/file.h> + +/** + * I/O Manager Routines + * http://msdn.microsoft.com/en-us/library/windows/hardware/ff551797/ + * + * These routines are only accessible to kernel drivers, but we need + * similar functionality in WinPR in user space. + * + * This is a best effort non-conflicting port of this API meant for + * non-Windows, WinPR usage only. + * + * References: + * + * Device Objects and Device Stacks: + * http://msdn.microsoft.com/en-us/library/windows/hardware/ff543153/ + * + * Driver Development Part 1: Introduction to Drivers: + * http://www.codeproject.com/Articles/9504/Driver-Development-Part-1-Introduction-to-Drivers/ + */ + +#define DEVICE_FILE_PREFIX_PATH "\\Device\\" + +static char* GetDeviceFileNameWithoutPrefixA(LPCSTR lpName) +{ + char* lpFileName = NULL; + + if (!lpName) + return NULL; + + if (strncmp(lpName, DEVICE_FILE_PREFIX_PATH, sizeof(DEVICE_FILE_PREFIX_PATH) - 1) != 0) + return NULL; + + lpFileName = + _strdup(&lpName[strnlen(DEVICE_FILE_PREFIX_PATH, sizeof(DEVICE_FILE_PREFIX_PATH))]); + return lpFileName; +} + +static char* GetDeviceFileUnixDomainSocketBaseFilePathA(void) +{ + char* lpTempPath = NULL; + char* lpPipePath = NULL; + lpTempPath = GetKnownPath(KNOWN_PATH_TEMP); + + if (!lpTempPath) + return NULL; + + lpPipePath = GetCombinedPath(lpTempPath, ".device"); + free(lpTempPath); + return lpPipePath; +} + +static char* GetDeviceFileUnixDomainSocketFilePathA(LPCSTR lpName) +{ + char* lpPipePath = NULL; + char* lpFileName = NULL; + char* lpFilePath = NULL; + lpPipePath = GetDeviceFileUnixDomainSocketBaseFilePathA(); + + if (!lpPipePath) + return NULL; + + lpFileName = GetDeviceFileNameWithoutPrefixA(lpName); + + if (!lpFileName) + { + free(lpPipePath); + return NULL; + } + + lpFilePath = GetCombinedPath(lpPipePath, (char*)lpFileName); + free(lpPipePath); + free(lpFileName); + return lpFilePath; +} + +/** + * IoCreateDevice: + * http://msdn.microsoft.com/en-us/library/windows/hardware/ff548397/ + */ + +NTSTATUS _IoCreateDeviceEx(PDRIVER_OBJECT_EX DriverObject, ULONG DeviceExtensionSize, + PUNICODE_STRING DeviceName, DEVICE_TYPE DeviceType, + ULONG DeviceCharacteristics, BOOLEAN Exclusive, + PDEVICE_OBJECT_EX* DeviceObject) +{ + int status = 0; + char* DeviceBasePath = NULL; + DEVICE_OBJECT_EX* pDeviceObjectEx = NULL; + DeviceBasePath = GetDeviceFileUnixDomainSocketBaseFilePathA(); + + if (!DeviceBasePath) + return STATUS_NO_MEMORY; + + if (!winpr_PathFileExists(DeviceBasePath)) + { + if (mkdir(DeviceBasePath, S_IRUSR | S_IWUSR | S_IXUSR) != 0) + { + free(DeviceBasePath); + return STATUS_ACCESS_DENIED; + } + } + + free(DeviceBasePath); + pDeviceObjectEx = (DEVICE_OBJECT_EX*)calloc(1, sizeof(DEVICE_OBJECT_EX)); + + if (!pDeviceObjectEx) + return STATUS_NO_MEMORY; + + pDeviceObjectEx->DeviceName = + ConvertWCharNToUtf8Alloc(DeviceName->Buffer, DeviceName->Length / sizeof(WCHAR), NULL); + if (!pDeviceObjectEx->DeviceName) + { + free(pDeviceObjectEx); + return STATUS_NO_MEMORY; + } + + pDeviceObjectEx->DeviceFileName = + GetDeviceFileUnixDomainSocketFilePathA(pDeviceObjectEx->DeviceName); + + if (!pDeviceObjectEx->DeviceFileName) + { + free(pDeviceObjectEx->DeviceName); + free(pDeviceObjectEx); + return STATUS_NO_MEMORY; + } + + if (winpr_PathFileExists(pDeviceObjectEx->DeviceFileName)) + { + if (unlink(pDeviceObjectEx->DeviceFileName) == -1) + { + free(pDeviceObjectEx->DeviceName); + free(pDeviceObjectEx->DeviceFileName); + free(pDeviceObjectEx); + return STATUS_ACCESS_DENIED; + } + } + + status = mkfifo(pDeviceObjectEx->DeviceFileName, 0666); + + if (status != 0) + { + free(pDeviceObjectEx->DeviceName); + free(pDeviceObjectEx->DeviceFileName); + free(pDeviceObjectEx); + + switch (errno) + { + case EACCES: + return STATUS_ACCESS_DENIED; + + case EEXIST: + return STATUS_OBJECT_NAME_EXISTS; + + case ENAMETOOLONG: + return STATUS_NAME_TOO_LONG; + + case ENOENT: + case ENOTDIR: + return STATUS_NOT_A_DIRECTORY; + + case ENOSPC: + return STATUS_DISK_FULL; + + default: + return STATUS_INTERNAL_ERROR; + } + } + + *((ULONG_PTR*)(DeviceObject)) = (ULONG_PTR)pDeviceObjectEx; + return STATUS_SUCCESS; +} + +/** + * IoDeleteDevice: + * http://msdn.microsoft.com/en-us/library/windows/hardware/ff549083/ + */ + +VOID _IoDeleteDeviceEx(PDEVICE_OBJECT_EX DeviceObject) +{ + DEVICE_OBJECT_EX* pDeviceObjectEx = NULL; + pDeviceObjectEx = (DEVICE_OBJECT_EX*)DeviceObject; + + if (!pDeviceObjectEx) + return; + + unlink(pDeviceObjectEx->DeviceFileName); + free(pDeviceObjectEx->DeviceName); + free(pDeviceObjectEx->DeviceFileName); + free(pDeviceObjectEx); +} + +#endif diff --git a/winpr/libwinpr/io/io.c b/winpr/libwinpr/io/io.c new file mode 100644 index 0000000..2df20be --- /dev/null +++ b/winpr/libwinpr/io/io.c @@ -0,0 +1,276 @@ +/** + * WinPR: Windows Portable Runtime + * Asynchronous I/O Functions + * + * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <winpr/config.h> + +#include <winpr/io.h> + +#ifndef _WIN32 + +#ifdef WINPR_HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <time.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dirent.h> + +#include <fcntl.h> +#include <sys/un.h> +#include <sys/stat.h> +#include <sys/socket.h> + +#include <winpr/crt.h> +#include <winpr/wlog.h> + +#include "../handle/handle.h" +#include "../pipe/pipe.h" +#include "../log.h" + +#define TAG WINPR_TAG("io") + +BOOL GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, + LPDWORD lpNumberOfBytesTransferred, BOOL bWait) +{ +#if 1 + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +#else + ULONG Type; + WINPR_HANDLE* Object; + + if (!winpr_Handle_GetInfo(hFile, &Type, &Object)) + return FALSE; + + else if (Type == HANDLE_TYPE_NAMED_PIPE) + { + int status = -1; + DWORD request; + PVOID lpBuffer; + DWORD nNumberOfBytes; + WINPR_NAMED_PIPE* pipe; + + pipe = (WINPR_NAMED_PIPE*)Object; + + if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)) + return FALSE; + + lpBuffer = lpOverlapped->Pointer; + request = (DWORD)lpOverlapped->Internal; + nNumberOfBytes = (DWORD)lpOverlapped->InternalHigh; + + if (request == 0) + { + if (pipe->clientfd == -1) + return FALSE; + + status = read(pipe->clientfd, lpBuffer, nNumberOfBytes); + } + else if (request == 1) + { + if (pipe->clientfd == -1) + return FALSE; + + status = write(pipe->clientfd, lpBuffer, nNumberOfBytes); + } + else if (request == 2) + { + socklen_t length; + struct sockaddr_un s = { 0 }; + + if (pipe->serverfd == -1) + return FALSE; + + length = sizeof(struct sockaddr_un); + + status = accept(pipe->serverfd, (struct sockaddr*)&s, &length); + + if (status < 0) + return FALSE; + + pipe->clientfd = status; + pipe->ServerMode = FALSE; + + status = 0; + } + + if (status < 0) + { + *lpNumberOfBytesTransferred = 0; + return FALSE; + } + + *lpNumberOfBytesTransferred = status; + } + + return TRUE; +#endif +} + +BOOL GetOverlappedResultEx(HANDLE hFile, LPOVERLAPPED lpOverlapped, + LPDWORD lpNumberOfBytesTransferred, DWORD dwMilliseconds, + BOOL bAlertable) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +BOOL DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +HANDLE CreateIoCompletionPort(HANDLE FileHandle, HANDLE ExistingCompletionPort, + ULONG_PTR CompletionKey, DWORD NumberOfConcurrentThreads) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return NULL; +} + +BOOL GetQueuedCompletionStatus(HANDLE CompletionPort, LPDWORD lpNumberOfBytesTransferred, + PULONG_PTR lpCompletionKey, LPOVERLAPPED* lpOverlapped, + DWORD dwMilliseconds) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +BOOL GetQueuedCompletionStatusEx(HANDLE CompletionPort, LPOVERLAPPED_ENTRY lpCompletionPortEntries, + ULONG ulCount, PULONG ulNumEntriesRemoved, DWORD dwMilliseconds, + BOOL fAlertable) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +BOOL PostQueuedCompletionStatus(HANDLE CompletionPort, DWORD dwNumberOfBytesTransferred, + ULONG_PTR dwCompletionKey, LPOVERLAPPED lpOverlapped) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +BOOL CancelIo(HANDLE hFile) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +BOOL CancelIoEx(HANDLE hFile, LPOVERLAPPED lpOverlapped) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +BOOL CancelSynchronousIo(HANDLE hThread) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +#endif + +#ifdef _UWP + +#include <winpr/crt.h> +#include <winpr/wlog.h> + +#include "../log.h" + +#define TAG WINPR_TAG("io") + +BOOL GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, + LPDWORD lpNumberOfBytesTransferred, BOOL bWait) +{ + return GetOverlappedResultEx(hFile, lpOverlapped, lpNumberOfBytesTransferred, + bWait ? INFINITE : 0, TRUE); +} + +BOOL DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +HANDLE CreateIoCompletionPort(HANDLE FileHandle, HANDLE ExistingCompletionPort, + ULONG_PTR CompletionKey, DWORD NumberOfConcurrentThreads) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return NULL; +} + +BOOL GetQueuedCompletionStatus(HANDLE CompletionPort, LPDWORD lpNumberOfBytesTransferred, + PULONG_PTR lpCompletionKey, LPOVERLAPPED* lpOverlapped, + DWORD dwMilliseconds) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +BOOL GetQueuedCompletionStatusEx(HANDLE CompletionPort, LPOVERLAPPED_ENTRY lpCompletionPortEntries, + ULONG ulCount, PULONG ulNumEntriesRemoved, DWORD dwMilliseconds, + BOOL fAlertable) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +BOOL PostQueuedCompletionStatus(HANDLE CompletionPort, DWORD dwNumberOfBytesTransferred, + ULONG_PTR dwCompletionKey, LPOVERLAPPED lpOverlapped) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +BOOL CancelIo(HANDLE hFile) +{ + return CancelIoEx(hFile, NULL); +} + +BOOL CancelSynchronousIo(HANDLE hThread) +{ + WLog_ERR(TAG, "Not implemented"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +#endif diff --git a/winpr/libwinpr/io/io.h b/winpr/libwinpr/io/io.h new file mode 100644 index 0000000..17d0013 --- /dev/null +++ b/winpr/libwinpr/io/io.h @@ -0,0 +1,37 @@ +/** + * WinPR: Windows Portable Runtime + * Asynchronous I/O Functions + * + * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WINPR_IO_PRIVATE_H +#define WINPR_IO_PRIVATE_H + +#ifndef _WIN32 + +#include <winpr/io.h> + +#include "../handle/handle.h" + +typedef struct +{ + char* DeviceName; + char* DeviceFileName; +} DEVICE_OBJECT_EX; + +#endif + +#endif /* WINPR_IO_PRIVATE_H */ diff --git a/winpr/libwinpr/io/test/CMakeLists.txt b/winpr/libwinpr/io/test/CMakeLists.txt new file mode 100644 index 0000000..ca40897 --- /dev/null +++ b/winpr/libwinpr/io/test/CMakeLists.txt @@ -0,0 +1,25 @@ + +set(MODULE_NAME "TestIo") +set(MODULE_PREFIX "TEST_IO") + +set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) + +set(${MODULE_PREFIX}_TESTS + TestIoGetOverlappedResult.c) + +create_test_sourcelist(${MODULE_PREFIX}_SRCS + ${${MODULE_PREFIX}_DRIVER} + ${${MODULE_PREFIX}_TESTS}) + +add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + +target_link_libraries(${MODULE_NAME} winpr) + +set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") + +foreach(test ${${MODULE_PREFIX}_TESTS}) + get_filename_component(TestName ${test} NAME_WE) + add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName}) +endforeach() + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test") diff --git a/winpr/libwinpr/io/test/TestIoGetOverlappedResult.c b/winpr/libwinpr/io/test/TestIoGetOverlappedResult.c new file mode 100644 index 0000000..044eb11 --- /dev/null +++ b/winpr/libwinpr/io/test/TestIoGetOverlappedResult.c @@ -0,0 +1,10 @@ + +#include <stdio.h> +#include <winpr/io.h> +#include <winpr/crt.h> +#include <winpr/windows.h> + +int TestIoGetOverlappedResult(int argc, char* argv[]) +{ + return 0; +} |