From 204ae5462a34a104c72b32bfb2da2918f57a32dc Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Wed, 9 Sep 2015 15:48:59 +0200 Subject: [PATCH 1/6] winpr/file: refactoring The used method for initalizing and registering the handle creators had certain disadvantages like that it was necessary to have the creators initialized before the first call to CreateFile. In case of comm it wouldn't have been possible to open an comm port without calling any other call related function first. Now the handle creators are initialized the first time CreateFile is called. This way it is also possible to ensure a certain order of the handler invocations. This commit also splits out the client side named pipe code from the generic file handling (now called generic.c instead of file.c) and uses the new handle creator infrastructure to register. --- winpr/libwinpr/comm/comm.c | 41 +- winpr/libwinpr/file/CMakeLists.txt | 2 +- winpr/libwinpr/file/{file.c => generic.c} | 375 ++---------------- winpr/libwinpr/file/namedPipeClient.c | 287 ++++++++++++++ winpr/libwinpr/handle/handle.h | 4 +- .../pipe/test/TestPipeCreateNamedPipe.c | 10 +- 6 files changed, 345 insertions(+), 374 deletions(-) rename winpr/libwinpr/file/{file.c => generic.c} (65%) create mode 100644 winpr/libwinpr/file/namedPipeClient.c diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c index 5f84e04bb..dd1e3868f 100644 --- a/winpr/libwinpr/comm/comm.c +++ b/winpr/libwinpr/comm/comm.c @@ -71,7 +71,7 @@ typedef struct comm_device COMM_DEVICE; static COMM_DEVICE **_CommDevices = NULL; static CRITICAL_SECTION _CommDevicesLock; -static HANDLE_CREATOR *_CommHandleCreator = NULL; +static HANDLE_CREATOR _CommHandleCreator; static pthread_once_t _CommInitialized = PTHREAD_ONCE_INIT; @@ -85,14 +85,19 @@ static int CommGetFd(HANDLE handle) return comm->fd; } -static void _CommInit() +HANDLE_CREATOR *GetCommHandleCreator(void) +{ + _CommHandleCreator.IsHandled = IsCommDevice; + _CommHandleCreator.CreateFileA = CommCreateFileA; + return &_CommHandleCreator; +} + +static void _CommInit(void) { /* NB: error management to be done outside of this function */ assert(_Log == NULL); assert(_CommDevices == NULL); - assert(_CommHandleCreator == NULL); - _CommDevices = (COMM_DEVICE**)calloc(COMM_DEVICE_MAX+1, sizeof(COMM_DEVICE*)); if (!_CommDevices) @@ -105,32 +110,10 @@ static void _CommInit() return; } - _CommHandleCreator = (HANDLE_CREATOR*)malloc(sizeof(HANDLE_CREATOR)); - if (!_CommHandleCreator) - { - DeleteCriticalSection(&_CommDevicesLock); - free(_CommDevices); - _CommDevices = NULL; - return; - } - - _CommHandleCreator->IsHandled = IsCommDevice; - _CommHandleCreator->CreateFileA = CommCreateFileA; - - if (!RegisterHandleCreator(_CommHandleCreator)) - { - DeleteCriticalSection(&_CommDevicesLock); - free(_CommDevices); - free(_CommHandleCreator); - _CommDevices = NULL; - _CommHandleCreator = NULL; - return; - } _Log = WLog_Get("com.winpr.comm"); assert(_Log != NULL); } - /** * Returns TRUE when the comm module is correctly intialized, FALSE otherwise * with ERROR_DLL_INIT_FAILED set as the last error. @@ -143,12 +126,6 @@ static BOOL CommInitialized() return FALSE; } - if (_CommHandleCreator == NULL) - { - SetLastError(ERROR_DLL_INIT_FAILED); - return FALSE; - } - return TRUE; } diff --git a/winpr/libwinpr/file/CMakeLists.txt b/winpr/libwinpr/file/CMakeLists.txt index 034d5c1c0..55a8e84bb 100644 --- a/winpr/libwinpr/file/CMakeLists.txt +++ b/winpr/libwinpr/file/CMakeLists.txt @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -winpr_module_add(file.c pattern.c) +winpr_module_add(generic.c namedPipeClient.c pattern.c) if(BUILD_TESTING) add_subdirectory(test) diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/generic.c similarity index 65% rename from winpr/libwinpr/file/file.c rename to winpr/libwinpr/file/generic.c index c154df6f3..c71d17af8 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/generic.c @@ -25,11 +25,6 @@ #include #include #include -#include -#include -#include -#include - #include #ifdef HAVE_UNISTD_H @@ -42,7 +37,34 @@ #include "../log.h" #define TAG WINPR_TAG("file") -#include + +#ifndef _WIN32 + +#include +#include +#include + +#include +#include +#include + +#ifdef HAVE_AIO_H +#undef HAVE_AIO_H /* disable for now, incomplete */ +#endif + +#ifdef HAVE_AIO_H +#include +#endif + +#ifdef ANDROID +#include +#else +#include +#endif + +#include "../handle/handle.h" + +#include "../pipe/pipe.h" /** * api-ms-win-core-file-l1-2-0.dll: @@ -148,172 +170,27 @@ * http://code.google.com/p/kernel/wiki/AIOUserGuide */ -#ifndef _WIN32 - -#ifdef HAVE_UNISTD_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef HAVE_AIO_H -#undef HAVE_AIO_H /* disable for now, incomplete */ -#endif - -#ifdef HAVE_AIO_H -#include -#endif - -#ifndef _WIN32 -#include -#include -#include -#endif - -#ifdef ANDROID -#include -#else -#include -#endif - -#include "../handle/handle.h" - -#include "../pipe/pipe.h" - -/* TODO: FIXME: use of a wArrayList and split winpr-utils with - * winpr-collections to avoid a circular dependency - * _HandleCreators = ArrayList_New(TRUE); - */ -/* _HandleCreators is a NULL-terminated array with a maximun of HANDLE_CREATOR_MAX HANDLE_CREATOR */ -#define HANDLE_CREATOR_MAX 128 -static HANDLE_CREATOR** _HandleCreators = NULL; -static CRITICAL_SECTION _HandleCreatorsLock; +static wArrayList *_HandleCreators; static pthread_once_t _HandleCreatorsInitialized = PTHREAD_ONCE_INIT; -static BOOL FileCloseHandle(HANDLE handle); -static BOOL FileIsHandled(HANDLE handle) -{ - WINPR_NAMED_PIPE* pFile = (WINPR_NAMED_PIPE*) handle; - - if (!pFile || (pFile->Type != HANDLE_TYPE_NAMED_PIPE) || (pFile == INVALID_HANDLE_VALUE)) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - return TRUE; -} - -BOOL FileCloseHandle(HANDLE handle) { - WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*) handle; - - - if (!FileIsHandled(handle)) - return FALSE; - - if (pNamedPipe->clientfd != -1) - { - //WLOG_DBG(TAG, "closing clientfd %d", pNamedPipe->clientfd); - close(pNamedPipe->clientfd); - } - - if (pNamedPipe->serverfd != -1) - { - //WLOG_DBG(TAG, "closing serverfd %d", pNamedPipe->serverfd); - close(pNamedPipe->serverfd); - } - - if (pNamedPipe->pfnUnrefNamedPipe) - pNamedPipe->pfnUnrefNamedPipe(pNamedPipe); - - free(pNamedPipe->lpFileName); - free(pNamedPipe->lpFilePath); - free(pNamedPipe->name); - free(pNamedPipe); - - return TRUE; -} - -static int FileGetFd(HANDLE handle) -{ - WINPR_NAMED_PIPE *file = (WINPR_NAMED_PIPE *)handle; - - if (!FileIsHandled(handle)) - return -1; - - if (file->ServerMode) - return file->serverfd; - else - return file->clientfd; -} +HANDLE_CREATOR *GetNamedPipeClientHandleCreator(void); +HANDLE_CREATOR *GetCommHandleCreator(void); static void _HandleCreatorsInit() { - /* NB: error management to be done outside of this function */ + assert(_HandleCreators == NULL); - _HandleCreators = (HANDLE_CREATOR**)calloc(HANDLE_CREATOR_MAX+1, sizeof(HANDLE_CREATOR*)); + _HandleCreators = ArrayList_New(TRUE); if (!_HandleCreators) return; - if (!InitializeCriticalSectionEx(&_HandleCreatorsLock, 0, 0)) - { - free(_HandleCreators); - _HandleCreators = NULL; - } -} - -/** - * Returns TRUE on success, FALSE otherwise. - * - * ERRORS: - * ERROR_DLL_INIT_FAILED - * ERROR_INSUFFICIENT_BUFFER _HandleCreators full - */ -BOOL RegisterHandleCreator(PHANDLE_CREATOR pHandleCreator) -{ - int i; - - if (pthread_once(&_HandleCreatorsInitialized, _HandleCreatorsInit) != 0) - { - SetLastError(ERROR_DLL_INIT_FAILED); - return FALSE; - } - - if (_HandleCreators == NULL) - { - SetLastError(ERROR_DLL_INIT_FAILED); - return FALSE; - } - - EnterCriticalSection(&_HandleCreatorsLock); - - for (i=0; iIsHandled(lpFileName)) { HANDLE newHandle = creator->CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); - LeaveCriticalSection(&_HandleCreatorsLock); + ArrayList_Unlock(_HandleCreators); return newHandle; } } - LeaveCriticalSection(&_HandleCreatorsLock); - - /* TODO: use of a HANDLE_CREATOR for named pipes as well */ - - if (!IsNamedPipeFileNameA(lpFileName)) - return INVALID_HANDLE_VALUE; - - name = GetNamedPipeNameWithoutPrefixA(lpFileName); - - if (!name) - return INVALID_HANDLE_VALUE; - - free(name); - pNamedPipe = (WINPR_NAMED_PIPE*) calloc(1, sizeof(WINPR_NAMED_PIPE)); - if (!pNamedPipe) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return INVALID_HANDLE_VALUE; - } - - hNamedPipe = (HANDLE) pNamedPipe; - WINPR_HANDLE_SET_TYPE_AND_MODE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE, WINPR_FD_READ); - pNamedPipe->name = _strdup(lpFileName); - if (!pNamedPipe->name) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - free(pNamedPipe); - return INVALID_HANDLE_VALUE; - } - pNamedPipe->dwOpenMode = 0; - pNamedPipe->dwPipeMode = 0; - pNamedPipe->nMaxInstances = 0; - pNamedPipe->nOutBufferSize = 0; - pNamedPipe->nInBufferSize = 0; - pNamedPipe->nDefaultTimeOut = 0; - pNamedPipe->dwFlagsAndAttributes = dwFlagsAndAttributes; - pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName); - if (!pNamedPipe->lpFileName) - { - free((void *)pNamedPipe->name); - free(pNamedPipe); - return INVALID_HANDLE_VALUE; - - } - pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName); - if (!pNamedPipe->lpFilePath) - { - free((void *)pNamedPipe->lpFileName); - free((void *)pNamedPipe->name); - free(pNamedPipe); - return INVALID_HANDLE_VALUE; - - } - pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0); - pNamedPipe->serverfd = -1; - pNamedPipe->ServerMode = FALSE; - ZeroMemory(&s, sizeof(struct sockaddr_un)); - s.sun_family = AF_UNIX; - strcpy(s.sun_path, pNamedPipe->lpFilePath); - status = connect(pNamedPipe->clientfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un)); - - pNamedPipe->ops = &ops; - - if (status != 0) - { - close(pNamedPipe->clientfd); - free((char*) pNamedPipe->name); - free((char*) pNamedPipe->lpFileName); - free((char*) pNamedPipe->lpFilePath); - free(pNamedPipe); - return INVALID_HANDLE_VALUE; - } - - if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED) - { -#if 0 - int flags = fcntl(pNamedPipe->clientfd, F_GETFL); - - if (flags != -1) - fcntl(pNamedPipe->clientfd, F_SETFL, flags | O_NONBLOCK); - -#endif - } - - return hNamedPipe; + ArrayList_Unlock(_HandleCreators); + return INVALID_HANDLE_VALUE; } HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, @@ -807,72 +586,6 @@ BOOL RemoveDirectoryW(LPCWSTR lpPathName) /* Extended API */ -#define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\" - -BOOL IsNamedPipeFileNameA(LPCSTR lpName) -{ - if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0) - return FALSE; - - return TRUE; -} - -char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName) -{ - char* lpFileName; - - if (!lpName) - return NULL; - - if (!IsNamedPipeFileNameA(lpName)) - return NULL; - - lpFileName = _strdup(&lpName[strlen(NAMED_PIPE_PREFIX_PATH)]); - return lpFileName; -} - -char* GetNamedPipeUnixDomainSocketBaseFilePathA() -{ - char* lpTempPath; - char* lpPipePath; - lpTempPath = GetKnownPath(KNOWN_PATH_TEMP); - if (!lpTempPath) - return NULL; - lpPipePath = GetCombinedPath(lpTempPath, ".pipe"); - free(lpTempPath); - return lpPipePath; -} - -char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName) -{ - char* lpPipePath; - char* lpFileName; - char* lpFilePath; - lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA(); - lpFileName = GetNamedPipeNameWithoutPrefixA(lpName); - lpFilePath = GetCombinedPath(lpPipePath, (char*) lpFileName); - free(lpPipePath); - free(lpFileName); - return lpFilePath; -} - -int GetNamePipeFileDescriptor(HANDLE hNamedPipe) -{ -#ifndef _WIN32 - int fd; - WINPR_NAMED_PIPE* pNamedPipe; - pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe; - - if (!pNamedPipe || pNamedPipe->Type != HANDLE_TYPE_NAMED_PIPE) - return -1; - - fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd; - return fd; -#else - return -1; -#endif -} - int UnixChangeFileMode(const char* filename, int flags) { #ifndef _WIN32 diff --git a/winpr/libwinpr/file/namedPipeClient.c b/winpr/libwinpr/file/namedPipeClient.c new file mode 100644 index 000000000..2941d313e --- /dev/null +++ b/winpr/libwinpr/file/namedPipeClient.c @@ -0,0 +1,287 @@ +/** + * WinPR: Windows Portable Runtime + * File Functions + * + * Copyright 2012 Marc-Andre Moreau + * Copyright 2014 Hewlett-Packard Development Company, L.P. + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 bernhard.miklautz@thincast.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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "../log.h" +#define TAG WINPR_TAG("file") + +#ifndef _WIN32 + + +#ifdef ANDROID +#include +#else +#include +#endif + +#include "../handle/handle.h" + +#include "../pipe/pipe.h" + +static HANDLE_CREATOR _NamedPipeClientHandleCreator; + +static BOOL NamedPipeClientIsHandled(HANDLE handle) +{ + WINPR_NAMED_PIPE* pFile = (WINPR_NAMED_PIPE*) handle; + + if (!pFile || (pFile->Type != HANDLE_TYPE_NAMED_PIPE) || (pFile == INVALID_HANDLE_VALUE)) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + return TRUE; +} + +BOOL NamedPipeClientCloseHandle(HANDLE handle) { + WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*) handle; + + + if (!NamedPipeClientIsHandled(handle)) + return FALSE; + + if (pNamedPipe->clientfd != -1) + { + //WLOG_DBG(TAG, "closing clientfd %d", pNamedPipe->clientfd); + close(pNamedPipe->clientfd); + } + + if (pNamedPipe->serverfd != -1) + { + //WLOG_DBG(TAG, "closing serverfd %d", pNamedPipe->serverfd); + close(pNamedPipe->serverfd); + } + + if (pNamedPipe->pfnUnrefNamedPipe) + pNamedPipe->pfnUnrefNamedPipe(pNamedPipe); + + free(pNamedPipe->lpFileName); + free(pNamedPipe->lpFilePath); + free(pNamedPipe->name); + free(pNamedPipe); + + return TRUE; +} + +static int NamedPipeClientGetFd(HANDLE handle) +{ + WINPR_NAMED_PIPE *file = (WINPR_NAMED_PIPE *)handle; + + if (!NamedPipeClientIsHandled(handle)) + return -1; + + if (file->ServerMode) + return file->serverfd; + else + return file->clientfd; +} + +static HANDLE_OPS ops = { + NamedPipeClientIsHandled, + NamedPipeClientCloseHandle, + NamedPipeClientGetFd, + NULL, /* CleanupHandle */ + NamedPipeRead, + NamedPipeWrite +}; + +static HANDLE NamedPipeClientCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) +{ + char* name; + int status; + HANDLE hNamedPipe; + struct sockaddr_un s; + WINPR_NAMED_PIPE* pNamedPipe; + + if (!lpFileName) + return INVALID_HANDLE_VALUE; + + if (!IsNamedPipeFileNameA(lpFileName)) + return INVALID_HANDLE_VALUE; + + name = GetNamedPipeNameWithoutPrefixA(lpFileName); + + if (!name) + return INVALID_HANDLE_VALUE; + + free(name); + pNamedPipe = (WINPR_NAMED_PIPE*) calloc(1, sizeof(WINPR_NAMED_PIPE)); + if (!pNamedPipe) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return INVALID_HANDLE_VALUE; + } + + hNamedPipe = (HANDLE) pNamedPipe; + WINPR_HANDLE_SET_TYPE_AND_MODE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE, WINPR_FD_READ); + pNamedPipe->name = _strdup(lpFileName); + if (!pNamedPipe->name) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + free(pNamedPipe); + return INVALID_HANDLE_VALUE; + } + pNamedPipe->dwOpenMode = 0; + pNamedPipe->dwPipeMode = 0; + pNamedPipe->nMaxInstances = 0; + pNamedPipe->nOutBufferSize = 0; + pNamedPipe->nInBufferSize = 0; + pNamedPipe->nDefaultTimeOut = 0; + pNamedPipe->dwFlagsAndAttributes = dwFlagsAndAttributes; + pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName); + if (!pNamedPipe->lpFileName) + { + free((void *)pNamedPipe->name); + free(pNamedPipe); + return INVALID_HANDLE_VALUE; + + } + pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName); + if (!pNamedPipe->lpFilePath) + { + free((void *)pNamedPipe->lpFileName); + free((void *)pNamedPipe->name); + free(pNamedPipe); + return INVALID_HANDLE_VALUE; + + } + pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0); + pNamedPipe->serverfd = -1; + pNamedPipe->ServerMode = FALSE; + ZeroMemory(&s, sizeof(struct sockaddr_un)); + s.sun_family = AF_UNIX; + strcpy(s.sun_path, pNamedPipe->lpFilePath); + status = connect(pNamedPipe->clientfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un)); + + pNamedPipe->ops = &ops; + + if (status != 0) + { + close(pNamedPipe->clientfd); + free((char*) pNamedPipe->name); + free((char*) pNamedPipe->lpFileName); + free((char*) pNamedPipe->lpFilePath); + free(pNamedPipe); + return INVALID_HANDLE_VALUE; + } + + if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED) + { +#if 0 + int flags = fcntl(pNamedPipe->clientfd, F_GETFL); + + if (flags != -1) + fcntl(pNamedPipe->clientfd, F_SETFL, flags | O_NONBLOCK); + +#endif + } + + return hNamedPipe; +} + +HANDLE_CREATOR *GetNamedPipeClientHandleCreator(void) +{ + _NamedPipeClientHandleCreator.IsHandled = IsNamedPipeFileNameA; + _NamedPipeClientHandleCreator.CreateFileA = NamedPipeClientCreateFileA; + return &_NamedPipeClientHandleCreator; +} + +#endif + +/* Extended API */ + +#define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\" + +BOOL IsNamedPipeFileNameA(LPCSTR lpName) +{ + if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0) + return FALSE; + + return TRUE; +} + +char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName) +{ + char* lpFileName; + + if (!lpName) + return NULL; + + if (!IsNamedPipeFileNameA(lpName)) + return NULL; + + lpFileName = _strdup(&lpName[strlen(NAMED_PIPE_PREFIX_PATH)]); + return lpFileName; +} + +char* GetNamedPipeUnixDomainSocketBaseFilePathA() +{ + char* lpTempPath; + char* lpPipePath; + lpTempPath = GetKnownPath(KNOWN_PATH_TEMP); + if (!lpTempPath) + return NULL; + lpPipePath = GetCombinedPath(lpTempPath, ".pipe"); + free(lpTempPath); + return lpPipePath; +} + +char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName) +{ + char* lpPipePath; + char* lpFileName; + char* lpFilePath; + lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA(); + lpFileName = GetNamedPipeNameWithoutPrefixA(lpName); + lpFilePath = GetCombinedPath(lpPipePath, (char*) lpFileName); + free(lpPipePath); + free(lpFileName); + return lpFilePath; +} + +int GetNamePipeFileDescriptor(HANDLE hNamedPipe) +{ +#ifndef _WIN32 + int fd; + WINPR_NAMED_PIPE* pNamedPipe; + pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe; + + if (!pNamedPipe || pNamedPipe->Type != HANDLE_TYPE_NAMED_PIPE) + return -1; + + fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd; + return fd; +#else + return -1; +#endif +} + diff --git a/winpr/libwinpr/handle/handle.h b/winpr/libwinpr/handle/handle.h index 728cd8160..7dd620062 100644 --- a/winpr/libwinpr/handle/handle.h +++ b/winpr/libwinpr/handle/handle.h @@ -102,7 +102,7 @@ static INLINE int winpr_Handle_getFd(HANDLE handle) if (!winpr_Handle_GetInfo(handle, &type, &hdl)) return -1; - if (!hdl || !hdl->ops->GetFd) + if (!hdl || !hdl->ops || !hdl->ops->GetFd) return -1; return hdl->ops->GetFd(handle); @@ -116,7 +116,7 @@ static INLINE DWORD winpr_Handle_cleanup(HANDLE handle) if (!winpr_Handle_GetInfo(handle, &type, &hdl)) return WAIT_FAILED; - if (!hdl) + if (!hdl || !hdl->ops) return WAIT_FAILED; /* If there is no cleanup function, assume all ok. */ diff --git a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c index abb1800b1..e8131f477 100644 --- a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c +++ b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c @@ -36,12 +36,6 @@ static void* named_pipe_client_thread(void* arg) WaitForSingleObject(ReadyEvent, INFINITE); hNamedPipe = CreateFile(lpszPipeNameMt, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); - if (!hNamedPipe) - { - printf("%s:Named Pipe CreateFile failure: NULL handle\n", __FUNCTION__); - goto out; - } - if (hNamedPipe == INVALID_HANDLE_VALUE) { printf("%s: Named Pipe CreateFile failure: INVALID_HANDLE_VALUE\n", __FUNCTION__); @@ -252,8 +246,8 @@ static void* named_pipe_single_thread(void* arg) for (i = 0; i < numPipes; i++) { - if (!(clients[i] = CreateFile(lpszPipeNameSt, GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, NULL))) + if ((clients[i] = CreateFile(lpszPipeNameSt, GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { printf("%s: CreateFile #%d failed\n", __FUNCTION__, i); goto out; From 6b52a2e5cc6a9eb2c76d53cca2205cbd940aa825 Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Wed, 9 Sep 2015 16:47:03 +0200 Subject: [PATCH 2/6] winpr/file: initial regular file support Add initial support for "regular" files. First implemented call is GetStdHandle to get stdin/stdout/stderr. --- winpr/include/winpr/environment.h | 4 - winpr/include/winpr/file.h | 9 +- winpr/libwinpr/environment/environment.c | 15 -- winpr/libwinpr/file/CMakeLists.txt | 2 +- winpr/libwinpr/file/file.c | 222 ++++++++++++++++++ winpr/libwinpr/file/generic.c | 1 - winpr/libwinpr/file/namedPipeClient.c | 3 +- winpr/libwinpr/file/test/CMakeLists.txt | 4 +- .../libwinpr/file/test/TestFileGetStdHandle.c | 46 ++++ 9 files changed, 281 insertions(+), 25 deletions(-) create mode 100644 winpr/libwinpr/file/file.c create mode 100644 winpr/libwinpr/file/test/TestFileGetStdHandle.c diff --git a/winpr/include/winpr/environment.h b/winpr/include/winpr/environment.h index 71bdc056c..d6329d827 100644 --- a/winpr/include/winpr/environment.h +++ b/winpr/include/winpr/environment.h @@ -40,10 +40,6 @@ WINPR_API BOOL SetCurrentDirectoryW(LPCWSTR lpPathName); WINPR_API DWORD SearchPathA(LPCSTR lpPath, LPCSTR lpFileName, LPCSTR lpExtension, DWORD nBufferLength, LPSTR lpBuffer, LPSTR* lpFilePart); WINPR_API DWORD SearchPathW(LPCWSTR lpPath, LPCWSTR lpFileName, LPCWSTR lpExtension, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR* lpFilePart); -WINPR_API HANDLE GetStdHandle(DWORD nStdHandle); -WINPR_API BOOL SetStdHandle(DWORD nStdHandle, HANDLE hHandle); -WINPR_API BOOL SetStdHandleEx(DWORD dwStdHandle, HANDLE hNewHandle, HANDLE* phOldHandle); - WINPR_API LPSTR GetCommandLineA(VOID); WINPR_API LPWSTR GetCommandLineW(VOID); diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index 45ec3e698..4d3a3792f 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -161,6 +161,10 @@ #define FIND_FIRST_EX_CASE_SENSITIVE 0x1 #define FIND_FIRST_EX_LARGE_FETCH 0x2 +#define STD_INPUT_HANDLE (DWORD)-10 +#define STD_OUTPUT_HANDLE (DWORD)-11 +#define STD_ERROR_HANDLE (DWORD)-12 + typedef union _FILE_SEGMENT_ELEMENT { PVOID64 Buffer; @@ -316,7 +320,6 @@ WINPR_API BOOL RemoveDirectoryW(LPCWSTR lpPathName); #define RemoveDirectory RemoveDirectoryA #endif - /* Extra Functions */ typedef BOOL (*pcIsFileHandled)(LPCSTR lpFileName); @@ -329,7 +332,9 @@ typedef struct _HANDLE_CREATOR pcCreateFileA CreateFileA; } HANDLE_CREATOR, *PHANDLE_CREATOR, *LPHANDLE_CREATOR; -BOOL RegisterHandleCreator(PHANDLE_CREATOR pHandleCreator); +WINPR_API HANDLE GetStdHandle(DWORD nStdHandle); +WINPR_API BOOL SetStdHandle(DWORD nStdHandle, HANDLE hHandle); +WINPR_API BOOL SetStdHandleEx(DWORD dwStdHandle, HANDLE hNewHandle, HANDLE* phOldHandle); #endif /* _WIN32 */ diff --git a/winpr/libwinpr/environment/environment.c b/winpr/libwinpr/environment/environment.c index d87172679..dcdb24f30 100644 --- a/winpr/libwinpr/environment/environment.c +++ b/winpr/libwinpr/environment/environment.c @@ -111,21 +111,6 @@ DWORD SearchPathW(LPCWSTR lpPath, LPCWSTR lpFileName, LPCWSTR lpExtension, DWORD return 0; } -HANDLE GetStdHandle(DWORD nStdHandle) -{ - return NULL; -} - -BOOL SetStdHandle(DWORD nStdHandle, HANDLE hHandle) -{ - return TRUE; -} - -BOOL SetStdHandleEx(DWORD dwStdHandle, HANDLE hNewHandle, HANDLE* phOldHandle) -{ - return TRUE; -} - LPSTR GetCommandLineA(VOID) { return NULL; diff --git a/winpr/libwinpr/file/CMakeLists.txt b/winpr/libwinpr/file/CMakeLists.txt index 55a8e84bb..986c87386 100644 --- a/winpr/libwinpr/file/CMakeLists.txt +++ b/winpr/libwinpr/file/CMakeLists.txt @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -winpr_module_add(generic.c namedPipeClient.c pattern.c) +winpr_module_add(generic.c namedPipeClient.c pattern.c file.c) if(BUILD_TESTING) add_subdirectory(test) diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c new file mode 100644 index 000000000..b46ee4f06 --- /dev/null +++ b/winpr/libwinpr/file/file.c @@ -0,0 +1,222 @@ +/** + * WinPR: Windows Portable Runtime + * File Functions + * + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 Bernhard Miklautz + * + * 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 _WIN32 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + + +#include "../log.h" +#define TAG WINPR_TAG("file") + +#include +#include + +#include "../handle/handle.h" +#include + +struct winpr_file +{ + WINPR_HANDLE_DEF(); + + int fd; +}; + +typedef struct winpr_file WINPR_FILE; + +static BOOL FileIsHandled(HANDLE handle) +{ + WINPR_FILE* pFile = (WINPR_FILE*) handle; + + if (!pFile || (pFile->Type != HANDLE_TYPE_FILE)) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + return TRUE; +} + +static int FileGetFd(HANDLE handle) +{ + WINPR_FILE *file= (WINPR_FILE*)handle; + + if (!FileIsHandled(handle)) + return -1; + + return file->fd; +} + +static BOOL FileCloseHandle(HANDLE handle) { + WINPR_FILE* file = (WINPR_FILE *)handle; + + if (!FileIsHandled(handle)) + return FALSE; + + if (file->fd != -1) + { + close(file->fd); + file->fd = -1; + } + + free(handle); + return TRUE; +} + +static BOOL FileRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, + LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) +{ + int io_status; + WINPR_FILE* file; + BOOL status = TRUE; + + if (!Object) + return FALSE; + + if (lpOverlapped) + { + WLog_ERR(TAG, "Overlapping write not supported."); + return FALSE; + } + + file = (WINPR_FILE *)Object; + do + { + io_status = read(file->fd, lpBuffer, nNumberOfBytesToRead); + } + while ((io_status < 0) && (errno == EINTR)); + + if (io_status < 0) + { + status = FALSE; + + switch (errno) + { + case EWOULDBLOCK: + SetLastError(ERROR_NO_DATA); + break; + } + } + + if (lpNumberOfBytesRead) + *lpNumberOfBytesRead = io_status; + + return status; +} + +static BOOL FileWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) +{ + int io_status; + WINPR_FILE* file; + + if (!Object) + return FALSE; + + if (lpOverlapped) + { + WLog_ERR(TAG, "Overlapping write not supported."); + return FALSE; + } + + file = (WINPR_FILE *)Object; + + do + { + io_status = write(file->fd, lpBuffer, nNumberOfBytesToWrite); + } + while ((io_status < 0) && (errno == EINTR)); + + if ((io_status < 0) && (errno == EWOULDBLOCK)) + io_status = 0; + + *lpNumberOfBytesWritten = io_status; + return TRUE; +} + + +static HANDLE_OPS ops = { + FileIsHandled, + FileCloseHandle, + FileGetFd, + NULL, /* CleanupHandle */ + FileRead, + FileWrite +}; + +static WINPR_FILE *FileHandle_New() +{ + WINPR_FILE *pFile; + HANDLE hFile; + + pFile = (WINPR_FILE*) calloc(1, sizeof(WINPR_FILE)); + if (!pFile) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + pFile->fd = -1; + pFile->ops = &ops; + + hFile = (HANDLE) pFile; + WINPR_HANDLE_SET_TYPE_AND_MODE(pFile, HANDLE_TYPE_FILE, WINPR_FD_READ); + return pFile; +} + +HANDLE GetStdHandle(DWORD nStdHandle) +{ + int fd; + WINPR_FILE *pFile; + switch (nStdHandle) + { + case STD_INPUT_HANDLE: + fd = STDIN_FILENO; + break; + case STD_OUTPUT_HANDLE: + fd = STDOUT_FILENO; + break; + case STD_ERROR_HANDLE: + fd = STDERR_FILENO; + break; + default: + return INVALID_HANDLE_VALUE; + } + pFile = FileHandle_New(); + if (!pFile) + return INVALID_HANDLE_VALUE; + + pFile->fd = fd; + return (HANDLE)pFile; +} + +BOOL SetStdHandle(DWORD nStdHandle, HANDLE hHandle) +{ + return TRUE; +} + +BOOL SetStdHandleEx(DWORD dwStdHandle, HANDLE hNewHandle, HANDLE* phOldHandle) +{ + return TRUE; +} + +#endif /* _WIN32 */ + diff --git a/winpr/libwinpr/file/generic.c b/winpr/libwinpr/file/generic.c index c71d17af8..9eac8e165 100644 --- a/winpr/libwinpr/file/generic.c +++ b/winpr/libwinpr/file/generic.c @@ -24,7 +24,6 @@ #include #include -#include #include #ifdef HAVE_UNISTD_H diff --git a/winpr/libwinpr/file/namedPipeClient.c b/winpr/libwinpr/file/namedPipeClient.c index 2941d313e..d2aed74fd 100644 --- a/winpr/libwinpr/file/namedPipeClient.c +++ b/winpr/libwinpr/file/namedPipeClient.c @@ -61,7 +61,8 @@ static BOOL NamedPipeClientIsHandled(HANDLE handle) return TRUE; } -BOOL NamedPipeClientCloseHandle(HANDLE handle) { +BOOL NamedPipeClientCloseHandle(HANDLE handle) +{ WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*) handle; diff --git a/winpr/libwinpr/file/test/CMakeLists.txt b/winpr/libwinpr/file/test/CMakeLists.txt index f23bde6e9..c7015c670 100644 --- a/winpr/libwinpr/file/test/CMakeLists.txt +++ b/winpr/libwinpr/file/test/CMakeLists.txt @@ -12,7 +12,9 @@ set(${MODULE_PREFIX}_TESTS TestFilePatternMatch.c TestFileFindFirstFile.c TestFileFindFirstFileEx.c - TestFileFindNextFile.c) + TestFileFindNextFile.c + TestFileGetStdHandle.c +) create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} diff --git a/winpr/libwinpr/file/test/TestFileGetStdHandle.c b/winpr/libwinpr/file/test/TestFileGetStdHandle.c new file mode 100644 index 000000000..e37dd8cd7 --- /dev/null +++ b/winpr/libwinpr/file/test/TestFileGetStdHandle.c @@ -0,0 +1,46 @@ + +/** + * WinPR: Windows Portable Runtime + * File Functions + * + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 Bernhard Miklautz + * + * 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 +#include +#include + +int TestFileGetStdHandle(int argc, char* argv[]) +{ + HANDLE stdout; + char *buf = "happy happy"; + DWORD bytesWritten; + + stdout = GetStdHandle(STD_OUTPUT_HANDLE); + if (stdout == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "GetStdHandle failed ;(\n"); + return -1; + } + WriteFile(stdout, buf, strlen(buf), &bytesWritten, FALSE); + if (bytesWritten != strlen(buf)) + { + fprintf(stderr, "write failed\n"); + return -1; + } + + return 0; +} \ No newline at end of file From 8091530779249d30a8554454c412c5ea6a0085ab Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Wed, 9 Sep 2015 16:59:03 +0200 Subject: [PATCH 3/6] winpr/file: fix ios build comm is only build on linux. --- winpr/libwinpr/file/generic.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/winpr/libwinpr/file/generic.c b/winpr/libwinpr/file/generic.c index 9eac8e165..8b6b446ff 100644 --- a/winpr/libwinpr/file/generic.c +++ b/winpr/libwinpr/file/generic.c @@ -175,7 +175,10 @@ static pthread_once_t _HandleCreatorsInitialized = PTHREAD_ONCE_INIT; HANDLE_CREATOR *GetNamedPipeClientHandleCreator(void); + +#if defined __linux__ && !defined ANDROID HANDLE_CREATOR *GetCommHandleCreator(void); +#endif /* __linux__ && !defined ANDROID */ static void _HandleCreatorsInit() { @@ -189,7 +192,9 @@ static void _HandleCreatorsInit() * Register all file handle creators. */ ArrayList_Add(_HandleCreators, GetNamedPipeClientHandleCreator()); +#if defined __linux__ && !defined ANDROID ArrayList_Add(_HandleCreators, GetCommHandleCreator()); +#endif /* __linux__ && !defined ANDROID */ } From 0f5e7c60a79a826690bbe8a3aa67c7f7255fb65d Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Wed, 9 Sep 2015 17:07:40 +0200 Subject: [PATCH 4/6] winpr/file: don't close stdin/stdout/stderr If the handle is closed stdin/stdout/stderr should be left open. --- winpr/libwinpr/file/file.c | 9 +++++++-- winpr/libwinpr/file/test/TestFileGetStdHandle.c | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index b46ee4f06..4735ff232 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -74,8 +74,13 @@ static BOOL FileCloseHandle(HANDLE handle) { if (file->fd != -1) { - close(file->fd); - file->fd = -1; + + /* Don't close stdin/stdout/stderr */ + if (file->fd > 2) + { + close(file->fd); + file->fd = -1; + } } free(handle); diff --git a/winpr/libwinpr/file/test/TestFileGetStdHandle.c b/winpr/libwinpr/file/test/TestFileGetStdHandle.c index e37dd8cd7..07d00f8c3 100644 --- a/winpr/libwinpr/file/test/TestFileGetStdHandle.c +++ b/winpr/libwinpr/file/test/TestFileGetStdHandle.c @@ -41,6 +41,7 @@ int TestFileGetStdHandle(int argc, char* argv[]) fprintf(stderr, "write failed\n"); return -1; } + CloseHandle(stdout); return 0; } \ No newline at end of file From 0d9dfb974d67401ab3ccab7eacf60b17c3637b60 Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Thu, 10 Sep 2015 11:50:10 +0200 Subject: [PATCH 5/6] winpr/file: integrate pull request feedback * simplify RemoveDirectory * move std handle function into an extern C block --- winpr/include/winpr/file.h | 8 ++++---- winpr/libwinpr/file/generic.c | 5 +---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index 4d3a3792f..6d3e9cc54 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -298,6 +298,10 @@ WINPR_API BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecu WINPR_API BOOL RemoveDirectoryA(LPCSTR lpPathName); WINPR_API BOOL RemoveDirectoryW(LPCWSTR lpPathName); +WINPR_API HANDLE GetStdHandle(DWORD nStdHandle); +WINPR_API BOOL SetStdHandle(DWORD nStdHandle, HANDLE hHandle); +WINPR_API BOOL SetStdHandleEx(DWORD dwStdHandle, HANDLE hNewHandle, HANDLE* phOldHandle); + #ifdef __cplusplus } #endif @@ -332,10 +336,6 @@ typedef struct _HANDLE_CREATOR pcCreateFileA CreateFileA; } HANDLE_CREATOR, *PHANDLE_CREATOR, *LPHANDLE_CREATOR; -WINPR_API HANDLE GetStdHandle(DWORD nStdHandle); -WINPR_API BOOL SetStdHandle(DWORD nStdHandle, HANDLE hHandle); -WINPR_API BOOL SetStdHandleEx(DWORD dwStdHandle, HANDLE hNewHandle, HANDLE* phOldHandle); - #endif /* _WIN32 */ #define WILDCARD_STAR 0x00000001 diff --git a/winpr/libwinpr/file/generic.c b/winpr/libwinpr/file/generic.c index 8b6b446ff..6a8a265c6 100644 --- a/winpr/libwinpr/file/generic.c +++ b/winpr/libwinpr/file/generic.c @@ -575,10 +575,7 @@ BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttrib BOOL RemoveDirectoryA(LPCSTR lpPathName) { - if (!rmdir(lpPathName)) - return TRUE; - - return FALSE; + return (rmdir(lpPathName) == 0); } BOOL RemoveDirectoryW(LPCWSTR lpPathName) From e685f13e0bae3971ae9a8b9ae6adbb4c18619247 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 10 Sep 2015 13:26:37 +0200 Subject: [PATCH 6/6] Added ORIENTATION_PREFERENCE from WinUser.h. --- winpr/include/winpr/user.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/winpr/include/winpr/user.h b/winpr/include/winpr/user.h index 0499c7d6a..5edc6c87a 100644 --- a/winpr/include/winpr/user.h +++ b/winpr/include/winpr/user.h @@ -262,6 +262,16 @@ typedef struct tagBITMAPFILEHEADER DWORD bfOffBits; } BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER; +typedef enum _ORIENTATION_PREFERENCE +{ + ORIENTATION_PREFERENCE_NONE = 0x0, + ORIENTATION_PREFERENCE_LANDSCAPE = 0x1, + + ORIENTATION_PREFERENCE_PORTRAIT = 0x2, + ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED = 0x4, + ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED = 0x8 +} ORIENTATION_PREFERENCE; + #pragma pack(pop) #endif