diff --git a/libfreerdp/crypto/certificate.c b/libfreerdp/crypto/certificate.c index e8d292377..4e2618dfa 100644 --- a/libfreerdp/crypto/certificate.c +++ b/libfreerdp/crypto/certificate.c @@ -116,63 +116,55 @@ fail: static int certificate_data_match_legacy(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data) { - FILE* fp; + HANDLE fp; int match = 1; char* data; char* mdata; char* pline; char* hostname; - long size; + DWORD lowSize, highSize; + UINT64 size; size_t length; + DWORD read; - fp = fopen(certificate_store->legacy_file, "rb"); - if (!fp) + /* Assure POSIX style paths, CreateFile expects either '/' or '\\' */ + PathCchConvertStyleA(certificate_store->legacy_file, strlen(certificate_store->legacy_file), PATH_STYLE_UNIX); + fp = CreateFileA(certificate_store->legacy_file, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (fp == INVALID_HANDLE_VALUE) return match; - if (fseek(fp, 0, SEEK_END) < 0) + if ((lowSize = GetFileSize(fp, &highSize)) == INVALID_FILE_SIZE) { - WLog_ERR(TAG, "fseek(%s) returned %s [%08X]", - certificate_store->legacy_file, strerror(errno), errno); - fclose(fp); - return match; - } - if ((size = ftell(fp)) < 0) - { - WLog_ERR(TAG, "ftell(%s) returned %s [%08X]", - certificate_store->legacy_file, strerror(errno), errno); - fclose(fp); - return match; - } - if (fseek(fp, 0, SEEK_SET) < 0) - { - WLog_ERR(TAG, "fseek(%s) returned %s [%08X]", - certificate_store->legacy_file, strerror(errno), errno); - fclose(fp); + WLog_ERR(TAG, "GetFileSize(%s) returned %s [%08X]", + certificate_store->legacy_file, strerror(errno), GetLastError()); + CloseHandle(fp); return match; } + size = (UINT64)lowSize | ((UINT64)highSize << 32); if (size < 1) { - fclose(fp); + CloseHandle(fp); return match; } mdata = (char*) malloc(size + 2); if (!mdata) { - fclose(fp); + CloseHandle(fp); return match; } data = mdata; - if (fread(data, size, 1, fp) != 1) + if (!ReadFile(fp, data, size, &read, NULL) || (read != size)) { free(data); - fclose(fp); + CloseHandle(fp); return match; } - fclose(fp); + CloseHandle(fp); data[size] = '\n'; data[size + 1] = '\0'; @@ -243,67 +235,59 @@ static int certificate_data_match_raw(rdpCertificateStore* certificate_store, char** fprint) { BOOL found = FALSE; - FILE* fp; + HANDLE fp; size_t length; char* data; char* mdata; char* pline; int match = 1; - long int size; + DWORD lowSize, highSize; + UINT64 size; char* hostname = NULL; char* subject = NULL; char* issuer = NULL; char* fingerprint = NULL; unsigned short port = 0; + DWORD read; - fp = fopen(certificate_store->file, "rb"); + /* Assure POSIX style paths, CreateFile expects either '/' or '\\' */ + PathCchConvertStyleA(certificate_store->file, strlen(certificate_store->file), PATH_STYLE_UNIX); + fp = CreateFileA(certificate_store->file, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NORMAL, NULL); - if (!fp) + if (fp == INVALID_HANDLE_VALUE) return match; - if (fseek(fp, 0, SEEK_END) < 0) + if ((lowSize = GetFileSize(fp, &highSize)) == INVALID_FILE_SIZE) { - WLog_ERR(TAG, "fseek(%s) returned %s [%08X]", - certificate_store->file, strerror(errno), errno); - fclose(fp); - return match; - } - if ((size = ftell(fp)) < 0) - { - WLog_ERR(TAG, "ftell(%s) returned %s [%08X]", - certificate_store->file, strerror(errno), errno); - fclose(fp); - return match; - } - if (fseek(fp, 0, SEEK_SET) < 0) - { - WLog_ERR(TAG, "fseek(%s) returned %s [%08X]", - certificate_store->file, strerror(errno), errno); - fclose(fp); + WLog_ERR(TAG, "GetFileSize(%s) returned %s [%08X]", + certificate_store->legacy_file, strerror(errno), GetLastError()); + CloseHandle(fp); return match; } + size = (UINT64)lowSize | ((UINT64)highSize << 32); if (size < 1) { - fclose(fp); + CloseHandle(fp); return match; } mdata = (char*) malloc(size + 2); if (!mdata) { - fclose(fp); + CloseHandle(fp); return match; } data = mdata; - if (fread(data, size, 1, fp) != 1) + if (!ReadFile(fp, data, size, &read, NULL) || (read != size)) { - fclose(fp); free(data); + CloseHandle(fp); return match; } - fclose(fp); + CloseHandle(fp); data[size] = '\n'; data[size + 1] = '\0'; @@ -371,40 +355,36 @@ int certificate_data_match(rdpCertificateStore* certificate_store, BOOL certificate_data_replace(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data) { - FILE* fp; + HANDLE fp; BOOL rc = FALSE; size_t length; char* data; char* sdata; char* pline; - long int size; + UINT64 size; + DWORD read, written; + DWORD lowSize, highSize; - fp = fopen(certificate_store->file, "rb"); + /* Assure POSIX style paths, CreateFile expects either '/' or '\\' */ + PathCchConvertStyleA(certificate_store->file, strlen(certificate_store->file), PATH_STYLE_UNIX); + fp = CreateFileA(certificate_store->file, GENERIC_READ | GENERIC_WRITE, 0, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (!fp) + if (fp == INVALID_HANDLE_VALUE) return FALSE; - /* Read the current contents of the file. */ - if (fseek(fp, 0, SEEK_END) < 0) + + if ((lowSize = GetFileSize(fp, &highSize)) == INVALID_FILE_SIZE) { - WLog_ERR(TAG, "fseek(%s) returned %s [%08X]", - certificate_store->file, strerror(errno), errno); - fclose(fp); + WLog_ERR(TAG, "GetFileSize(%s) returned %s [%08X]", + certificate_store->legacy_file, strerror(errno), GetLastError()); + CloseHandle(fp); return FALSE; } + size = (UINT64)lowSize | ((UINT64)highSize << 32); - if ((size = ftell(fp)) < 0) + if (size < 1) { - WLog_ERR(TAG, "ftell(%s) returned %s [%08X]", - certificate_store->file, strerror(errno), errno); - fclose(fp); - return FALSE; - } - - if (fseek(fp, 0, SEEK_SET) < 0) - { - WLog_ERR(TAG, "fseek(%s) returned %s [%08X]", - certificate_store->file, strerror(errno), errno); - fclose(fp); + CloseHandle(fp); return FALSE; } @@ -415,22 +395,28 @@ BOOL certificate_data_replace(rdpCertificateStore* certificate_store, return FALSE; } - if (fread(data, size, 1, fp) != 1) + if (!ReadFile(fp, data, size, &read, NULL) || (read != size)) { - fclose(fp); free(data); + CloseHandle(fp); return FALSE; } - fclose(fp); - - fp = fopen(certificate_store->file, "wb"); - - if (fp == NULL) + if (SetFilePointer(fp, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { - WLog_ERR(TAG, "freopen(%s) returned %s [%08X]", - certificate_store->file, strerror(errno), errno); + WLog_ERR(TAG, "SetFilePointer(%s) returned %s [%08X]", + certificate_store->file, strerror(errno), GetLastError()); free(data); + CloseHandle(fp); + return FALSE; + } + + if (!SetEndOfFile(fp)) + { + WLog_ERR(TAG, "SetEndOfFile(%s) returned %s [%08X]", + certificate_store->file, strerror(errno), GetLastError()); + free(data); + CloseHandle(fp); return FALSE; } @@ -451,6 +437,7 @@ BOOL certificate_data_replace(rdpCertificateStore* certificate_store, char* fingerprint = NULL; char* subject = NULL; char* issuer = NULL; + char* tdata; if (!certificate_split_line(pline, &hostname, &port, &subject, &issuer, &fingerprint)) WLog_WARN(TAG, "Skipping invalid %s entry %s!", @@ -464,26 +451,44 @@ BOOL certificate_data_replace(rdpCertificateStore* certificate_store, fingerprint = certificate_data->fingerprint; rc = TRUE; } - if (fprintf(fp, "%s %hu %s %s %s\n", hostname, port, fingerprint, subject, issuer) < 0) + + size = _snprintf(NULL, 0, "%s %hu %s %s %s\n", hostname, port, fingerprint, subject, issuer); + tdata = malloc(size + 1); + if (!tdata) { - WLog_ERR(TAG, "fprintf(%s) returned %s [%08X]", + WLog_ERR(TAG, "malloc(%s) returned %s [%08X]", certificate_store->file, strerror(errno), errno); - fclose(fp); + free(data); + CloseHandle(fp); return FALSE; } + + if (_snprintf(tdata, size + 1, "%s %hu %s %s %s\n", hostname, port, fingerprint, subject, issuer) != size) + { + WLog_ERR(TAG, "_snprintf(%s) returned %s [%08X]", + certificate_store->file, strerror(errno), errno); + free(tdata); + free(data); + CloseHandle(fp); + return FALSE; + } + if (!WriteFile(fp, tdata, size, &written, NULL) || (written != size)) + { + WLog_ERR(TAG, "WriteFile(%s) returned %s [%08X]", + certificate_store->file, strerror(errno), errno); + free(tdata); + free(data); + CloseHandle(fp); + return FALSE; + } + free(tdata); } } pline = StrSep(&sdata, "\r\n"); } - if (fflush(fp) != 0) - { - WLog_WARN(TAG, "fflush(%s) returned %s [%08X]", - certificate_store->file, strerror(errno), errno); - } - - fclose(fp); + CloseHandle(fp); free(data); return rc; @@ -533,39 +538,60 @@ BOOL certificate_split_line(char* line, char** host, UINT16* port, char** subjec BOOL certificate_data_print(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data) { - FILE* fp; + HANDLE fp; + char* tdata; + UINT64 size; + DWORD written; /* reopen in append mode */ - fp = fopen(certificate_store->file, "ab"); + /* Assure POSIX style paths, CreateFile expects either '/' or '\\' */ + PathCchConvertStyleA(certificate_store->file, strlen(certificate_store->file), PATH_STYLE_UNIX); + fp = CreateFileA(certificate_store->file, GENERIC_WRITE, 0, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (!fp) + if (fp == INVALID_HANDLE_VALUE) return FALSE; - if (fseek(fp, 0, SEEK_END) < 0) + if (SetFilePointer(fp, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) { - WLog_ERR(TAG, "fseek(%s) returned %s [%08X]", - certificate_store->file, strerror(errno), errno); - fclose(fp); + WLog_ERR(TAG, "SetFilePointer(%s) returned %s [%08X]", + certificate_store->file, strerror(errno), GetLastError()); + CloseHandle(fp); return FALSE; } - if (fprintf(fp, "%s %hu %s %s %s\n", certificate_data->hostname, certificate_data->port, + size = _snprintf(NULL, 0, "%s %hu %s %s %s\n", certificate_data->hostname, certificate_data->port, certificate_data->fingerprint, certificate_data->subject, - certificate_data->issuer) < 0) + certificate_data->issuer); + tdata = malloc(size + 1); + if (!tdata) { - WLog_ERR(TAG, "fprintf(%s) returned %s [%08X]", + WLog_ERR(TAG, "malloc(%s) returned %s [%08X]", certificate_store->file, strerror(errno), errno); - fclose(fp); + CloseHandle(fp); return FALSE; } - - if (fflush(fp) != 0) + if (_snprintf(tdata, size + 1, "%s %hu %s %s %s\n", certificate_data->hostname, certificate_data->port, + certificate_data->fingerprint, certificate_data->subject, + certificate_data->issuer) != size) { - WLog_WARN(TAG, "fflush(%s) returned %s [%08X]", + WLog_ERR(TAG, "_snprintf(%s) returned %s [%08X]", certificate_store->file, strerror(errno), errno); + free(tdata); + CloseHandle(fp); + return FALSE; } + if (!WriteFile(fp, tdata, size, &written, NULL) || (written != size)) + { + WLog_ERR(TAG, "WriteFile(%s) returned %s [%08X]", + certificate_store->file, strerror(errno), errno); + free(tdata); + CloseHandle(fp); + return FALSE; + } + free(tdata); - fclose(fp); + CloseHandle(fp); return TRUE; } diff --git a/winpr/include/winpr/debug.h b/winpr/include/winpr/debug.h index 3d2cde68a..362bafd5a 100644 --- a/winpr/include/winpr/debug.h +++ b/winpr/include/winpr/debug.h @@ -32,6 +32,7 @@ WINPR_API void* winpr_backtrace(DWORD size); WINPR_API void winpr_backtrace_free(void* buffer); WINPR_API char** winpr_backtrace_symbols(void* buffer, size_t* used); WINPR_API void winpr_backtrace_symbols_fd(void* buffer, int fd); +WINPR_API char* winpr_strerror(DWORD dw, char* dmsg, size_t size); #ifdef __cplusplus } diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index afe858878..f0129e212 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -165,6 +165,13 @@ #define STD_OUTPUT_HANDLE (DWORD)-11 #define STD_ERROR_HANDLE (DWORD)-12 +#define FILE_BEGIN 0 +#define FILE_CURRENT 1 +#define FILE_END 2 + +#define LOCKFILE_FAIL_IMMEDIATELY 1 +#define LOCKFILE_EXCLUSIVE_LOCK 2 + typedef union _FILE_SEGMENT_ELEMENT { PVOID64 Buffer; @@ -261,6 +268,8 @@ WINPR_API BOOL FlushFileBuffers(HANDLE hFile); WINPR_API BOOL SetEndOfFile(HANDLE hFile); +WINPR_API DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh); + WINPR_API DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h index ddcaeaf46..555d05306 100644 --- a/winpr/include/winpr/string.h +++ b/winpr/include/winpr/string.h @@ -153,6 +153,7 @@ WINPR_API int lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2); #endif #define sprintf_s snprintf +#define _snprintf snprintf #define _scprintf(_fmt, ...) snprintf(NULL, 0, _fmt, ## __VA_ARGS__) #define _scprintf(_fmt, ...) snprintf(NULL, 0, _fmt, ## __VA_ARGS__) diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index 49d6a5d96..066a76e16 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -30,19 +30,12 @@ #define TAG WINPR_TAG("file") #include +#include -#include "../handle/handle.h" +#include "file.h" #include #include - -struct winpr_file -{ - WINPR_HANDLE_DEF(); - - int fd; -}; - -typedef struct winpr_file WINPR_FILE; +#include static BOOL FileIsHandled(HANDLE handle) { @@ -64,7 +57,7 @@ static int FileGetFd(HANDLE handle) if (!FileIsHandled(handle)) return -1; - return file->fd; + return fileno(file->fp); } static BOOL FileCloseHandle(HANDLE handle) { @@ -73,25 +66,80 @@ static BOOL FileCloseHandle(HANDLE handle) { if (!FileIsHandled(handle)) return FALSE; - if (file->fd != -1) + if (file->fp) { - /* Don't close stdin/stdout/stderr */ - if (file->fd > 2) + if (fileno(file->fp) > 2) { - close(file->fd); - file->fd = -1; + fclose(file->fp); + file->fp = NULL; } } - free(handle); + free(file->lpFileName); + free(file); return TRUE; } +static BOOL FileSetEndOfFile(HANDLE hFile) +{ + WINPR_FILE* pFile = (WINPR_FILE*) hFile; + off_t size; + + if (!hFile) + return FALSE; + + size = ftell(pFile->fp); + if (ftruncate(fileno(pFile->fp), size) < 0) + { + WLog_ERR(TAG, "ftruncate %s failed with %s [%08X]", + pFile->lpFileName, strerror(errno), errno); + return FALSE; + } + + return TRUE; +} + + +static DWORD FileSetFilePointer(HANDLE hFile, LONG lDistanceToMove, + PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) +{ + WINPR_FILE* pFile = (WINPR_FILE*) hFile; + long offset = lDistanceToMove; + int whence; + + if (!hFile) + return INVALID_SET_FILE_POINTER; + + switch(dwMoveMethod) + { + case FILE_BEGIN: + whence = SEEK_SET; + break; + case FILE_END: + whence = SEEK_END; + break; + case FILE_CURRENT: + whence = SEEK_CUR; + break; + default: + return INVALID_SET_FILE_POINTER; + } + + if (fseek(pFile->fp, offset, whence)) + { + WLog_ERR(TAG, "fseek(%s) failed with %s [%08X]", pFile->lpFileName, + strerror(errno), errno); + return INVALID_SET_FILE_POINTER; + } + + return ftell(pFile->fp); +} + static BOOL FileRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) { - int io_status; + size_t io_status; WINPR_FILE* file; BOOL status = TRUE; @@ -105,13 +153,9 @@ static BOOL FileRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, } file = (WINPR_FILE *)Object; - do - { - io_status = read(file->fd, lpBuffer, nNumberOfBytesToRead); - } - while ((io_status < 0) && (errno == EINTR)); + io_status = fread(lpBuffer, nNumberOfBytesToRead, 1, file->fp); - if (io_status < 0) + if (io_status != 1) { status = FALSE; @@ -124,7 +168,7 @@ static BOOL FileRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, } if (lpNumberOfBytesRead) - *lpNumberOfBytesRead = io_status; + *lpNumberOfBytesRead = nNumberOfBytesToRead; return status; } @@ -132,7 +176,7 @@ static BOOL FileRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, static BOOL FileWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { - int io_status; + size_t io_status; WINPR_FILE* file; if (!Object) @@ -146,71 +190,377 @@ static BOOL FileWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrit file = (WINPR_FILE *)Object; - do - { - io_status = write(file->fd, lpBuffer, nNumberOfBytesToWrite); - } - while ((io_status < 0) && (errno == EINTR)); + io_status = fwrite(lpBuffer, nNumberOfBytesToWrite, 1, file->fp); + if (io_status != 1) + return FALSE; if ((io_status < 0) && (errno == EWOULDBLOCK)) io_status = 0; - *lpNumberOfBytesWritten = io_status; + *lpNumberOfBytesWritten = nNumberOfBytesToWrite; return TRUE; } +static DWORD FileGetFileSize(HANDLE Object, LPDWORD lpFileSizeHigh) +{ + WINPR_FILE* file; + long cur, size; -static HANDLE_OPS ops = { - FileIsHandled, - FileCloseHandle, - FileGetFd, - NULL, /* CleanupHandle */ - FileRead, - FileWrite + if (!Object) + return 0; + + file = (WINPR_FILE *)Object; + + cur = ftell(file->fp); + + if (cur < 0) + { + WLog_ERR(TAG, "ftell(%s) failed with %s [%08X]", file->lpFileName, + strerror(errno), errno); + return INVALID_FILE_SIZE; + } + + if (fseek(file->fp, 0, SEEK_END) != 0) + { + WLog_ERR(TAG, "fseek(%s) failed with %s [%08X]", file->lpFileName, + strerror(errno), errno); + return INVALID_FILE_SIZE; + } + + size = ftell(file->fp); + + if (size < 0) + { + WLog_ERR(TAG, "ftell(%s) failed with %s [%08X]", file->lpFileName, + strerror(errno), errno); + return INVALID_FILE_SIZE; + } + + if (fseek(file->fp, cur, SEEK_SET) != 0) + { + WLog_ERR(TAG, "ftell(%s) failed with %s [%08X]", file->lpFileName, + strerror(errno), errno); + return INVALID_FILE_SIZE; + } + + if (lpFileSizeHigh) + *lpFileSizeHigh = 0; + + return size; +} + +static BOOL FileLockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved, + DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, + LPOVERLAPPED lpOverlapped) + { + int lock; + WINPR_FILE* pFile = (WINPR_FILE*)hFile; + + if (!hFile) + return FALSE; + + if (pFile->bLocked) + { + WLog_ERR(TAG, "File %s already locked!", pFile->lpFileName); + return FALSE; + } + + if (lpOverlapped) + { + WLog_ERR(TAG, "lpOverlapped not implemented!"); + return FALSE; + } + + if (dwFlags & LOCKFILE_EXCLUSIVE_LOCK) + lock = LOCK_EX; + else + lock = LOCK_SH; + + if (dwFlags & LOCKFILE_FAIL_IMMEDIATELY) + lock |= LOCK_NB; + + if (flock(fileno(pFile->fp), lock) < 0) + { + WLog_ERR(TAG, "flock failed with %s [%08X]", + strerror(errno), errno); + return FALSE; + } + + pFile->bLocked = TRUE; + + return TRUE; +} + +static BOOL FileUnlockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, + DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh) +{ + WINPR_FILE* pFile = (WINPR_FILE*)hFile; + + if (!hFile) + return FALSE; + + if (!pFile->bLocked) + { + WLog_ERR(TAG, "File %s is not locked!", pFile->lpFileName); + return FALSE; + } + + if (flock(fileno(pFile->fp), LOCK_UN) < 0) + { + WLog_ERR(TAG, "flock(LOCK_UN) %s failed with %s [%08X]", + pFile->lpFileName, strerror(errno), errno); + return FALSE; + } + + return TRUE; +} + +static BOOL FileUnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, + DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped) +{ + WINPR_FILE* pFile = (WINPR_FILE*)hFile; + + if (!hFile) + return FALSE; + + if (!pFile->bLocked) + { + WLog_ERR(TAG, "File %s is not locked!", pFile->lpFileName); + return FALSE; + } + + if (lpOverlapped) + { + WLog_ERR(TAG, "lpOverlapped not implemented!"); + return FALSE; + } + + if (flock(fileno(pFile->fp), LOCK_UN) < 0) + { + WLog_ERR(TAG, "flock(LOCK_UN) %s failed with %s [%08X]", + pFile->lpFileName, strerror(errno), errno); + return FALSE; + } + + return TRUE; +} + +static HANDLE_OPS fileOps = { + FileIsHandled, + FileCloseHandle, + FileGetFd, + NULL, /* CleanupHandle */ + FileRead, + NULL, /* FileReadEx */ + NULL, /* FileReadScatter */ + FileWrite, + NULL, /* FileWriteEx */ + NULL, /* FileWriteGather */ + FileGetFileSize, + NULL, /* FlushFileBuffers */ + FileSetEndOfFile, + FileSetFilePointer, + NULL, /* SetFilePointerEx */ + NULL, /* FileLockFile */ + FileLockFileEx, + FileUnlockFile, + FileUnlockFileEx }; -static WINPR_FILE *FileHandle_New() +static HANDLE_OPS shmOps = { + FileIsHandled, + FileCloseHandle, + FileGetFd, + NULL, /* CleanupHandle */ + FileRead, + NULL, /* FileReadEx */ + NULL, /* FileReadScatter */ + FileWrite, + NULL, /* FileWriteEx */ + NULL, /* FileWriteGather */ + NULL, /* FileGetFileSize */ + NULL, /* FlushFileBuffers */ + NULL, /* FileSetEndOfFile */ + NULL, /* FileSetFilePointer */ + NULL, /* SetFilePointerEx */ + NULL, /* FileLockFile */ + NULL, /* FileLockFileEx */ + NULL, /* FileUnlockFile */ + NULL /* FileUnlockFileEx */ + +}; + + +static const char* FileGetMode(DWORD dwDesiredAccess, DWORD dwCreationDisposition, BOOL* create) +{ + BOOL writeable = dwDesiredAccess & GENERIC_WRITE; + + switch(dwCreationDisposition) + { + case CREATE_ALWAYS: + *create = TRUE; + return (writeable) ? "wb+" : "rwb"; + case CREATE_NEW: + *create = TRUE; + return "wb+"; + case OPEN_ALWAYS: + *create = TRUE; + return "rb+"; + case OPEN_EXISTING: + *create = FALSE; + return "rb+"; + case TRUNCATE_EXISTING: + *create = FALSE; + return "wb+"; + default: + *create = FALSE; + return ""; + } +} + +static HANDLE FileCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) +{ + WINPR_FILE* pFile; + BOOL create; + const char* mode = FileGetMode(dwDesiredAccess, dwCreationDisposition, &create); + int lock; + FILE* fp = NULL; + + pFile = (WINPR_FILE*) calloc(1, sizeof(WINPR_FILE)); + if (!pFile) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return INVALID_HANDLE_VALUE; + } + + WINPR_HANDLE_SET_TYPE_AND_MODE(pFile, HANDLE_TYPE_FILE, WINPR_FD_READ); + pFile->ops = &fileOps; + + pFile->lpFileName = _strdup(lpFileName); + if (!pFile->lpFileName) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + free(pFile); + return INVALID_HANDLE_VALUE; + } + + pFile->dwOpenMode = dwDesiredAccess; + pFile->dwShareMode = dwShareMode; + pFile->dwFlagsAndAttributes = dwFlagsAndAttributes; + pFile->lpSecurityAttributes = lpSecurityAttributes; + pFile->dwCreationDisposition = dwCreationDisposition; + pFile->hTemplateFile = hTemplateFile; + + if (create) + { + fp = fopen(pFile->lpFileName, "ab"); + if (!fp) + { + free(pFile->lpFileName); + free(pFile); + return INVALID_HANDLE_VALUE; + } + + fp = freopen(pFile->lpFileName, mode, fp); + } + + if (NULL == fp) + fp = fopen(pFile->lpFileName, mode); + + pFile->fp = fp; + if (!pFile->fp) + { + /* This case can occur when trying to open a + * not existing file without create flag. */ + free(pFile->lpFileName); + free(pFile); + return INVALID_HANDLE_VALUE; + } + + setvbuf(fp, NULL, _IONBF, 0); + + if (dwShareMode & FILE_SHARE_READ) + lock = LOCK_SH; + if (dwShareMode & FILE_SHARE_WRITE) + lock = LOCK_EX; + + if (dwShareMode & (FILE_SHARE_READ | FILE_SHARE_WRITE)) + { + if (flock(fileno(pFile->fp), lock) < 0) + { + WLog_ERR(TAG, "flock failed with %s [%08X]", + strerror(errno), errno); + FileCloseHandle(pFile); + return INVALID_HANDLE_VALUE; + } + + pFile->bLocked = TRUE; + } + + return pFile; +} + +BOOL IsFileDevice(LPCTSTR lpDeviceName) +{ + return TRUE; +} + +HANDLE_CREATOR _FileHandleCreator = +{ + IsFileDevice, + FileCreateFileA +}; + +HANDLE_CREATOR *GetFileHandleCreator(void) +{ + return &_FileHandleCreator; +} + + +static WINPR_FILE *FileHandle_New(FILE* fp) { WINPR_FILE *pFile; - HANDLE hFile; + char name[MAX_PATH]; + _snprintf(name, sizeof(name), "device_%d", fileno(fp)); pFile = (WINPR_FILE*) calloc(1, sizeof(WINPR_FILE)); if (!pFile) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; } - pFile->fd = -1; - pFile->ops = &ops; + pFile->fp = fp; + pFile->ops = &shmOps; + pFile->lpFileName = _strdup(name); - hFile = (HANDLE) pFile; WINPR_HANDLE_SET_TYPE_AND_MODE(pFile, HANDLE_TYPE_FILE, WINPR_FD_READ); return pFile; } HANDLE GetStdHandle(DWORD nStdHandle) { - int fd; + FILE* fp; WINPR_FILE *pFile; + switch (nStdHandle) { case STD_INPUT_HANDLE: - fd = STDIN_FILENO; + fp = stdin; break; case STD_OUTPUT_HANDLE: - fd = STDOUT_FILENO; + fp = stdout; break; case STD_ERROR_HANDLE: - fd = STDERR_FILENO; + fp = stderr; break; default: return INVALID_HANDLE_VALUE; } - pFile = FileHandle_New(); + pFile = FileHandle_New(fp); if (!pFile) return INVALID_HANDLE_VALUE; - pFile->fd = fd; return (HANDLE)pFile; } @@ -234,16 +584,33 @@ HANDLE GetFileHandleForFileDescriptor(int fd) return (HANDLE)_get_osfhandle(fd); #else /* WIN32 */ WINPR_FILE *pFile; + FILE* fp; + int flags; /* Make sure it's a valid fd */ if (fcntl(fd, F_GETFD) == -1 && errno == EBADF) return INVALID_HANDLE_VALUE; - pFile = FileHandle_New(); + flags = fcntl(fd, F_GETFL); + if (flags == -1) + return INVALID_HANDLE_VALUE; + + if (flags & O_WRONLY) + fp = fdopen(fd, "wb"); + else + fp = fdopen(fd, "rb"); + + if (!fp) + return INVALID_HANDLE_VALUE; + + setvbuf(fp, NULL, _IONBF, 0); + + pFile = FileHandle_New(fp); if (!pFile) return INVALID_HANDLE_VALUE; - pFile->fd = fd; + return (HANDLE)pFile; #endif /* WIN32 */ } + diff --git a/winpr/libwinpr/file/file.h b/winpr/libwinpr/file/file.h new file mode 100644 index 000000000..af0916753 --- /dev/null +++ b/winpr/libwinpr/file/file.h @@ -0,0 +1,61 @@ +/** + * WinPR: Windows Portable Runtime + * File Functions + * + * Copyright 2015 Armin Novak + * Copyright 2015 Thincast Technologies GmbH + * + * 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_FILE_PRIV_H +#define WINPR_FILE_PRIV_H + +#include +#include + +#include +#include +#include + +#ifndef _WIN32 + +#include +#include "../handle/handle.h" + +struct winpr_file +{ + WINPR_HANDLE_DEF(); + + FILE* fp; + + char* lpFileName; + + DWORD dwOpenMode; + DWORD dwShareMode; + DWORD dwFlagsAndAttributes; + + LPSECURITY_ATTRIBUTES lpSecurityAttributes; + DWORD dwCreationDisposition; + HANDLE hTemplateFile; + + BOOL bLocked; +}; +typedef struct winpr_file WINPR_FILE; + +HANDLE_CREATOR *GetFileHandleCreator(void); + +#endif /* _WIN32 */ + +#endif /* WINPR_FILE_PRIV_H */ + diff --git a/winpr/libwinpr/file/generic.c b/winpr/libwinpr/file/generic.c index 6a8a265c6..8719787ad 100644 --- a/winpr/libwinpr/file/generic.c +++ b/winpr/libwinpr/file/generic.c @@ -65,6 +65,8 @@ #include "../pipe/pipe.h" +#include "file.h" + /** * api-ms-win-core-file-l1-2-0.dll: * @@ -195,6 +197,7 @@ static void _HandleCreatorsInit() #if defined __linux__ && !defined ANDROID ArrayList_Add(_HandleCreators, GetCommHandleCreator()); #endif /* __linux__ && !defined ANDROID */ + ArrayList_Add(_HandleCreators, GetFileHandleCreator()); } @@ -253,8 +256,9 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, if (creator && creator->IsHandled(lpFileName)) { - HANDLE newHandle = creator->CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, - dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); + HANDLE newHandle = creator->CreateFileA(lpFileName, dwDesiredAccess, + dwShareMode, lpSecurityAttributes, dwCreationDisposition, + dwFlagsAndAttributes, hTemplateFile); ArrayList_Unlock(_HandleCreators); return newHandle; } @@ -267,7 +271,17 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { - return NULL; + LPSTR lpFileNameA = NULL; + HANDLE hdl; + + if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpFileNameA, 0, NULL, NULL)) + return NULL; + + hdl= CreateFileA(lpFileNameA, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); + free (lpFileNameA); + + return hdl; } BOOL DeleteFileA(LPCSTR lpFileName) @@ -279,7 +293,15 @@ BOOL DeleteFileA(LPCSTR lpFileName) BOOL DeleteFileW(LPCWSTR lpFileName) { - return TRUE; + LPSTR lpFileNameA = NULL; + BOOL rc = FALSE; + + if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpFileNameA, 0, NULL, NULL)) + return FALSE; + rc = DeleteFileA(lpFileNameA); + free (lpFileNameA); + + return rc; } BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, @@ -304,22 +326,55 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, handle = (WINPR_HANDLE *)hFile; if (handle->ops->ReadFile) - return handle->ops->ReadFile(handle, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped); + return handle->ops->ReadFile(handle, lpBuffer, nNumberOfBytesToRead, + lpNumberOfBytesRead, lpOverlapped); WLog_ERR(TAG, "ReadFile operation not implemented"); return FALSE; } BOOL ReadFileEx(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, - LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) + LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->ReadFileEx) + return handle->ops->ReadFileEx(handle, lpBuffer, nNumberOfBytesToRead, + lpOverlapped, lpCompletionRoutine); + + WLog_ERR(TAG, "ReadFileEx operation not implemented"); + return FALSE; + return TRUE; } BOOL ReadFileScatter(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], - DWORD nNumberOfBytesToRead, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped) + DWORD nNumberOfBytesToRead, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped) { - return TRUE; + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->ReadFileScatter) + return handle->ops->ReadFileScatter(handle, aSegmentArray, nNumberOfBytesToRead, + lpReserved, lpOverlapped); + + WLog_ERR(TAG, "ReadFileScatter operation not implemented"); + return FALSE; } BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, @@ -336,68 +391,236 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, handle = (WINPR_HANDLE *)hFile; if (handle->ops->WriteFile) - return handle->ops->WriteFile(handle, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped); + return handle->ops->WriteFile(handle, lpBuffer, nNumberOfBytesToWrite, + lpNumberOfBytesWritten, lpOverlapped); - WLog_ERR(TAG, "ReadFile operation not implemented"); + WLog_ERR(TAG, "WriteFile operation not implemented"); return FALSE; } BOOL WriteFileEx(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, - LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) + LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - return TRUE; + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->WriteFileEx) + return handle->ops->WriteFileEx(handle, lpBuffer, nNumberOfBytesToWrite, + lpOverlapped, lpCompletionRoutine); + + WLog_ERR(TAG, "WriteFileEx operation not implemented"); + return FALSE; } BOOL WriteFileGather(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], - DWORD nNumberOfBytesToWrite, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped) + DWORD nNumberOfBytesToWrite, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped) { - return TRUE; + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->WriteFileGather) + return handle->ops->WriteFileGather(handle, aSegmentArray, nNumberOfBytesToWrite, + lpReserved, lpOverlapped); + + WLog_ERR(TAG, "WriteFileGather operation not implemented"); + return FALSE; } BOOL FlushFileBuffers(HANDLE hFile) { - return TRUE; + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->FlushFileBuffers) + return handle->ops->FlushFileBuffers(handle); + + WLog_ERR(TAG, "FlushFileBuffers operation not implemented"); + return FALSE; } BOOL SetEndOfFile(HANDLE hFile) { - return TRUE; + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->SetEndOfFile) + return handle->ops->SetEndOfFile(handle); + + WLog_ERR(TAG, "SetEndOfFile operation not implemented"); + return FALSE; +} + +DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) +{ + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->GetFileSize) + return handle->ops->GetFileSize(handle, lpFileSizeHigh); + + WLog_ERR(TAG, "GetFileSize operation not implemented"); + return 0; } DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) { - return TRUE; + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->SetFilePointer) + return handle->ops->SetFilePointer(handle, lDistanceToMove, + lpDistanceToMoveHigh, dwMoveMethod); + + WLog_ERR(TAG, "SetFilePointer operation not implemented"); + return 0; } BOOL SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, - PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) + PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) { - return TRUE; + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->SetFilePointerEx) + return handle->ops->SetFilePointerEx(handle, liDistanceToMove, + lpNewFilePointer, dwMoveMethod); + + WLog_ERR(TAG, "SetFilePointerEx operation not implemented"); + return 0; } BOOL LockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh) { - return TRUE; + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->LockFile) + return handle->ops->LockFile(handle, dwFileOffsetLow, dwFileOffsetHigh, + nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh); + + WLog_ERR(TAG, "LockFile operation not implemented"); + return FALSE; } BOOL LockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved, - DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped) + DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped) { - return TRUE; + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->LockFileEx) + return handle->ops->LockFileEx(handle, dwFlags, dwReserved, + nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh, lpOverlapped); + + WLog_ERR(TAG, "LockFileEx operation not implemented"); + return FALSE; } BOOL UnlockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh) { - return TRUE; + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->UnlockFile) + return handle->ops->UnlockFile(handle, dwFileOffsetLow, dwFileOffsetHigh, + nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh); + + WLog_ERR(TAG, "UnLockFile operation not implemented"); + return FALSE; } BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped) { - return TRUE; + ULONG Type; + WINPR_HANDLE *handle; + + if (hFile == INVALID_HANDLE_VALUE) + return FALSE; + + if (!winpr_Handle_GetInfo(hFile, &Type, &handle)) + return FALSE; + + handle = (WINPR_HANDLE *)hFile; + if (handle->ops->UnlockFileEx) + return handle->ops->UnlockFileEx(handle, dwReserved, + nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh, lpOverlapped); + + WLog_ERR(TAG, "UnLockFileEx operation not implemented"); + return FALSE; } struct _WIN32_FILE_SEARCH diff --git a/winpr/libwinpr/file/namedPipeClient.c b/winpr/libwinpr/file/namedPipeClient.c index d2aed74fd..b78f8eb7c 100644 --- a/winpr/libwinpr/file/namedPipeClient.c +++ b/winpr/libwinpr/file/namedPipeClient.c @@ -111,7 +111,20 @@ static HANDLE_OPS ops = { NamedPipeClientGetFd, NULL, /* CleanupHandle */ NamedPipeRead, - NamedPipeWrite + NULL, /* FileReadEx */ + NULL, /* FileReadScatter */ + NamedPipeWrite, + NULL, /* FileWriteEx */ + NULL, /* FileWriteGather */ + NULL, /* FileGetFileSize */ + NULL, /* FlushFileBuffers */ + NULL, /* FileSetEndOfFile */ + NULL, /* FileSetFilePointer */ + NULL, /* SetFilePointerEx */ + NULL, /* FileLockFile */ + NULL, /* FileLockFileEx */ + NULL, /* FileUnlockFile */ + NULL /* FileUnlockFileEx */ }; static HANDLE NamedPipeClientCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, diff --git a/winpr/libwinpr/file/test/TestFileCreateFile.c b/winpr/libwinpr/file/test/TestFileCreateFile.c index 39b6a26c7..547d322af 100644 --- a/winpr/libwinpr/file/test/TestFileCreateFile.c +++ b/winpr/libwinpr/file/test/TestFileCreateFile.c @@ -2,9 +2,81 @@ #include #include #include +#include +#include #include int TestFileCreateFile(int argc, char* argv[]) { - return 0; + HANDLE handle; + HRESULT hr; + DWORD written; + const char buffer[] = "Some random text\r\njust want it done."; + char cmp[sizeof(buffer)]; + LPSTR name = GetKnownSubPath(KNOWN_PATH_TEMP, "CreateFile.testfile"); + + int rc = 0; + + if (!name) + return -1; + + /* On windows we would need '\\' or '/' as seperator. + * Single '\' do not work. */ + hr = PathCchConvertStyleA(name, strlen(name), PATH_STYLE_UNIX); + if (FAILED(hr)) + rc = -1; + + handle = CreateFileA(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, + CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + if (!handle) + { + free(name); + return -1; + } + + if (!PathFileExistsA(name)) + rc = -1; + + if (!WriteFile(handle, buffer, sizeof(buffer), &written, NULL)) + rc = -1; + + if (written != sizeof(buffer)) + rc = -1; + + written = SetFilePointer(handle, 5, NULL, FILE_BEGIN); + + if (written != 5) + rc = -1; + + written = SetFilePointer(handle, 0, NULL, FILE_CURRENT); + + if (written != 5) + rc = -1; + + written = SetFilePointer(handle, -5, NULL, FILE_CURRENT); + + if (written != 0) + rc = -1; + + if (!ReadFile(handle, cmp, sizeof(cmp), &written, NULL)) + rc = -1; + + if (written != sizeof(cmp)) + rc = -1; + + if (memcmp(buffer, cmp, sizeof(buffer))) + rc = -1; + + if (!CloseHandle(handle)) + rc = -1; + + if (!DeleteFileA(name)) + rc = -1; + + if (PathFileExistsA(name)) + rc = -1; + + free(name); + + return rc; } diff --git a/winpr/libwinpr/handle/handle.h b/winpr/libwinpr/handle/handle.h index 7dd620062..d2669baa7 100644 --- a/winpr/libwinpr/handle/handle.h +++ b/winpr/libwinpr/handle/handle.h @@ -50,9 +50,33 @@ typedef BOOL (*pcCloseHandle)(HANDLE handle); typedef int (*pcGetFd)(HANDLE handle); typedef DWORD (*pcCleanupHandle)(HANDLE handle); typedef BOOL (*pcReadFile)(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, - LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); + LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); +typedef BOOL (*pcReadFileEx)(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, + LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); +typedef BOOL (*pcReadFileScatter)(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], + DWORD nNumberOfBytesToRead, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped); typedef BOOL (*pcWriteFile)(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, - LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); + LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); +typedef BOOL (*pcWriteFileEx)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, + LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine); +typedef BOOL (*pcWriteFileGather)(HANDLE hFile, FILE_SEGMENT_ELEMENT aSegmentArray[], + DWORD nNumberOfBytesToWrite, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped); +typedef DWORD (*pcGetFileSize)(HANDLE handle, LPDWORD lpFileSizeHigh); +typedef BOOL (*pcFlushFileBuffers)(HANDLE hFile); +typedef BOOL (*pcSetEndOfFile)(HANDLE handle); +typedef DWORD(*pcSetFilePointer)(HANDLE handle, LONG lDistanceToMove, + PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); +typedef BOOL (*pcSetFilePointerEx)(HANDLE hFile, LARGE_INTEGER liDistanceToMove, + PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod); +typedef BOOL (*pcLockFile)(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, + DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh); +typedef BOOL (*pcLockFileEx)(HANDLE hFile, DWORD dwFlags, DWORD dwReserved, + DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, + LPOVERLAPPED lpOverlapped); +typedef BOOL (*pcUnlockFile)(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, + DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh); +typedef BOOL (*pcUnlockFileEx)(HANDLE hFile, DWORD dwReserved, DWORD nNumberOfBytesToUnlockLow, + DWORD nNumberOfBytesToUnlockHigh, LPOVERLAPPED lpOverlapped); typedef struct _HANDLE_OPS { @@ -61,7 +85,20 @@ typedef struct _HANDLE_OPS pcGetFd GetFd; pcCleanupHandle CleanupHandle; pcReadFile ReadFile; + pcReadFileEx ReadFileEx; + pcReadFileScatter ReadFileScatter; pcWriteFile WriteFile; + pcWriteFileEx WriteFileEx; + pcWriteFileGather WriteFileGather; + pcGetFileSize GetFileSize; + pcFlushFileBuffers FlushFileBuffers; + pcSetEndOfFile SetEndOfFile; + pcSetFilePointer SetFilePointer; + pcSetFilePointerEx SetFilePointerEx; + pcLockFile LockFile; + pcLockFileEx LockFileEx; + pcUnlockFile UnlockFile; + pcUnlockFileEx UnlockFileEx; } HANDLE_OPS; struct winpr_handle diff --git a/winpr/libwinpr/pipe/pipe.c b/winpr/libwinpr/pipe/pipe.c index 28d9eede3..02beb5d5b 100644 --- a/winpr/libwinpr/pipe/pipe.c +++ b/winpr/libwinpr/pipe/pipe.c @@ -178,7 +178,20 @@ static HANDLE_OPS ops = { PipeGetFd, NULL, /* CleanupHandle */ PipeRead, - PipeWrite + NULL, /* FileReadEx */ + NULL, /* FileReadScatter */ + PipeWrite, + NULL, /* FileWriteEx */ + NULL, /* FileWriteGather */ + NULL, /* FileGetFileSize */ + NULL, /* FlushFileBuffers */ + NULL, /* FileSetEndOfFile */ + NULL, /* FileSetFilePointer */ + NULL, /* SetFilePointerEx */ + NULL, /* FileLockFile */ + NULL, /* FileLockFileEx */ + NULL, /* FileUnlockFile */ + NULL /* FileUnlockFileEx */ }; @@ -409,6 +422,8 @@ static HANDLE_OPS namedOps = { NamedPipeGetFd, NULL, /* CleanupHandle */ NamedPipeRead, + NULL, + NULL, NamedPipeWrite }; diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c index d90d1e021..a911f424c 100644 --- a/winpr/libwinpr/utils/debug.c +++ b/winpr/libwinpr/utils/debug.c @@ -471,3 +471,29 @@ void winpr_log_backtrace(const char* tag, DWORD level, DWORD size) winpr_backtrace_free(stack); } +char* winpr_strerror(DWORD dw, char* dmsg, size_t size) { +#if defined(_WIN32) + LPTSTR msg = NULL; + DWORD rc; + + rc = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, dw, 0, (LPTSTR)&msg, 0, NULL); + if (rc) { +#if defined(UNICODE) + WideCharToMultiByte(CP_ACP, 0, msg, rc, dmsg, size - 1, NULL, NULL); +#else /* defined(UNICODE) */ + memcpy(dmsg, msg, min(rc, size - 1)); +#endif /* defined(UNICODE) */ + dmsg[min(rc, size - 1)] = 0; + LocalFree(msg); + } else { + _snprintf(dmsg, size, "FAILURE: %08X", GetLastError()); + } +#else /* defined(_WIN32) */ + _snprintf(dmsg, size, "%s", strerror(dw)); +#endif /* defined(_WIN32) */ + + return dmsg; +}