Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,22 @@
# WinPR: Windows Portable Runtime
# libwinpr-file 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(generic.c namedPipeClient.c namedPipeClient.h pattern.c file.c)
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@@ -0,0 +1,9 @@
set(MINWIN_LAYER "1")
set(MINWIN_GROUP "core")
set(MINWIN_MAJOR_VERSION "2")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "file")
set(MINWIN_LONG_NAME "File Functions")
set(MODULE_LIBRARY_NAME
"api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}"
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,66 @@
/**
* WinPR: Windows Portable Runtime
* File Functions
*
* Copyright 2015 Armin Novak <armin.novak@thincast.com>
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.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_FILE_PRIV_H
#define WINPR_FILE_PRIV_H
#include <winpr/winpr.h>
#include <winpr/wtypes.h>
#include <winpr/nt.h>
#include <winpr/io.h>
#include <winpr/error.h>
#ifndef _WIN32
#include <stdio.h>
#include "../handle/handle.h"
#define EPOCH_DIFF 11644473600LL
#define STAT_TIME_TO_FILETIME(_t) (((UINT64)(_t) + EPOCH_DIFF) * 10000000LL)
struct winpr_file
{
WINPR_HANDLE common;
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;
const HANDLE_CREATOR* GetFileHandleCreator(void);
UINT32 map_posix_err(int fs_errno);
#endif /* _WIN32 */
#endif /* WINPR_FILE_PRIV_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,286 @@
/**
* WinPR: Windows Portable Runtime
* File Functions
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* 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.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/file.h>
#ifdef WINPR_HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "../log.h"
#define TAG WINPR_TAG("file")
#ifndef _WIN32
#ifdef ANDROID
#include <sys/vfs.h>
#else
#include <sys/statvfs.h>
#endif
#include "../handle/handle.h"
#include "../pipe/pipe.h"
#include "namedPipeClient.h"
static BOOL NamedPipeClientIsHandled(HANDLE handle)
{
return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_NAMED_PIPE, TRUE);
}
static 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,
nullptr, /* CleanupHandle */
NamedPipeRead,
nullptr, /* FileReadEx */
nullptr, /* FileReadScatter */
NamedPipeWrite,
nullptr, /* FileWriteEx */
nullptr, /* FileWriteGather */
nullptr, /* FileGetFileSize */
nullptr, /* FlushFileBuffers */
nullptr, /* FileSetEndOfFile */
nullptr, /* FileSetFilePointer */
nullptr, /* SetFilePointerEx */
nullptr, /* FileLockFile */
nullptr, /* FileLockFileEx */
nullptr, /* FileUnlockFile */
nullptr, /* FileUnlockFileEx */
nullptr, /* SetFileTime */
nullptr, /* FileGetFileInformationByHandle */
};
static HANDLE
NamedPipeClientCreateFileA(LPCSTR lpFileName, WINPR_ATTR_UNUSED DWORD dwDesiredAccess,
WINPR_ATTR_UNUSED DWORD dwShareMode,
WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpSecurityAttributes,
WINPR_ATTR_UNUSED DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, WINPR_ATTR_UNUSED HANDLE hTemplateFile)
{
int status = 0;
struct sockaddr_un s = WINPR_C_ARRAY_INIT;
if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
{
WLog_ERR(TAG, "WinPR does not support the FILE_FLAG_OVERLAPPED flag");
SetLastError(ERROR_NOT_SUPPORTED);
return INVALID_HANDLE_VALUE;
}
if (!lpFileName)
return INVALID_HANDLE_VALUE;
if (!IsNamedPipeFileNameA(lpFileName))
return INVALID_HANDLE_VALUE;
WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1, sizeof(WINPR_NAMED_PIPE));
if (!pNamedPipe)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return INVALID_HANDLE_VALUE;
}
HANDLE 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);
goto fail;
}
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)
goto fail;
pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName);
if (!pNamedPipe->lpFilePath)
goto fail;
pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0);
if (pNamedPipe->clientfd < 0)
goto fail;
pNamedPipe->serverfd = -1;
pNamedPipe->ServerMode = FALSE;
s.sun_family = AF_UNIX;
(void)sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path), "%s", pNamedPipe->lpFilePath);
status = connect(pNamedPipe->clientfd, (struct sockaddr*)&s, sizeof(struct sockaddr_un));
pNamedPipe->common.ops = &ops;
if (status != 0)
goto fail;
if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
{
// TODO: Implement
WLog_ERR(TAG, "TODO: implement this");
}
return hNamedPipe;
fail:
if (pNamedPipe)
{
if (pNamedPipe->clientfd >= 0)
close(pNamedPipe->clientfd);
free(pNamedPipe->name);
free(pNamedPipe->lpFileName);
free(pNamedPipe->lpFilePath);
free(pNamedPipe);
}
return INVALID_HANDLE_VALUE;
}
const HANDLE_CREATOR* GetNamedPipeClientHandleCreator(void)
{
static const HANDLE_CREATOR NamedPipeClientHandleCreator = { .IsHandled = IsNamedPipeFileNameA,
.CreateFileA =
NamedPipeClientCreateFileA };
return &NamedPipeClientHandleCreator;
}
#endif
/* Extended API */
#define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\"
BOOL IsNamedPipeFileNameA(LPCSTR lpName)
{
return (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) == 0);
}
char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName)
{
char* lpFileName = nullptr;
if (!lpName)
return nullptr;
if (!IsNamedPipeFileNameA(lpName))
return nullptr;
lpFileName = _strdup(&lpName[strnlen(NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH))]);
return lpFileName;
}
char* GetNamedPipeUnixDomainSocketBaseFilePathA(void)
{
char* lpTempPath = nullptr;
char* lpPipePath = nullptr;
lpTempPath = GetKnownPath(KNOWN_PATH_TEMP);
if (!lpTempPath)
return nullptr;
lpPipePath = GetCombinedPath(lpTempPath, ".pipe");
free(lpTempPath);
return lpPipePath;
}
char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName)
{
char* lpPipePath = nullptr;
char* lpFileName = nullptr;
char* lpFilePath = nullptr;
lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA();
lpFileName = GetNamedPipeNameWithoutPrefixA(lpName);
lpFilePath = GetCombinedPath(lpPipePath, lpFileName);
free(lpPipePath);
free(lpFileName);
return lpFilePath;
}
int GetNamePipeFileDescriptor(HANDLE hNamedPipe)
{
#ifndef _WIN32
int fd = 0;
WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
if (!NamedPipeClientIsHandled(hNamedPipe))
return -1;
fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
return fd;
#else
return -1;
#endif
}

View File

@@ -0,0 +1,25 @@
/**
* WinPR: Windows Portable Runtime
* File Functions
*
* Copyright 2024 Armin Novak <anovak@thincast.com>
* Copyright 2024 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.
*/
#pragma once
#include <winpr/file.h>
extern const HANDLE_CREATOR* GetNamedPipeClientHandleCreator(void);

View File

@@ -0,0 +1,373 @@
/**
* WinPR: Windows Portable Runtime
* File 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/crt.h>
#include <winpr/handle.h>
#include <winpr/file.h>
#ifdef WINPR_HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef WINPR_HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include "../log.h"
#define TAG WINPR_TAG("file")
/**
* File System Behavior in the Microsoft Windows Environment:
* http://download.microsoft.com/download/4/3/8/43889780-8d45-4b2e-9d3a-c696a890309f/File%20System%20Behavior%20Overview.pdf
*/
LPSTR FilePatternFindNextWildcardA(LPCSTR lpPattern, DWORD* pFlags)
{
LPSTR lpWildcard = nullptr;
*pFlags = 0;
lpWildcard = strpbrk(lpPattern, "*?~");
if (lpWildcard)
{
if (*lpWildcard == '*')
{
*pFlags = WILDCARD_STAR;
return lpWildcard;
}
else if (*lpWildcard == '?')
{
*pFlags = WILDCARD_QM;
return lpWildcard;
}
else if (*lpWildcard == '~')
{
if (lpWildcard[1] == '*')
{
*pFlags = WILDCARD_DOS_STAR;
return lpWildcard;
}
else if (lpWildcard[1] == '?')
{
*pFlags = WILDCARD_DOS_QM;
return lpWildcard;
}
else if (lpWildcard[1] == '.')
{
*pFlags = WILDCARD_DOS_DOT;
return lpWildcard;
}
}
}
return nullptr;
}
static BOOL FilePatternMatchSubExpressionA(LPCSTR lpFileName, size_t cchFileName, LPCSTR lpX,
size_t cchX, LPCSTR lpY, size_t cchY, LPCSTR lpWildcard,
LPCSTR* ppMatchEnd)
{
LPCSTR lpMatch = nullptr;
if (!lpFileName)
return FALSE;
if (*lpWildcard == '*')
{
/*
* S
* <-----<
* X | | e Y
* X * Y == (0)----->-(1)->-----(2)-----(3)
*/
/*
* State 0: match 'X'
*/
if (_strnicmp(lpFileName, lpX, cchX) != 0)
return FALSE;
/*
* State 1: match 'S' or 'e'
*
* We use 'e' to transition to state 2
*/
/**
* State 2: match Y
*/
if (cchY != 0)
{
/* TODO: case insensitive character search */
lpMatch = strchr(&lpFileName[cchX], *lpY);
if (!lpMatch)
return FALSE;
if (_strnicmp(lpMatch, lpY, cchY) != 0)
return FALSE;
}
else
{
lpMatch = &lpFileName[cchFileName];
}
/**
* State 3: final state
*/
*ppMatchEnd = &lpMatch[cchY];
return TRUE;
}
else if (*lpWildcard == '?')
{
/**
* X S Y
* X ? Y == (0)---(1)---(2)---(3)
*/
/*
* State 0: match 'X'
*/
if (cchFileName < cchX)
return FALSE;
if (_strnicmp(lpFileName, lpX, cchX) != 0)
return FALSE;
/*
* State 1: match 'S'
*/
/**
* State 2: match Y
*/
if (cchY != 0)
{
/* TODO: case insensitive character search */
lpMatch = strchr(&lpFileName[cchX + 1], *lpY);
if (!lpMatch)
return FALSE;
if (_strnicmp(lpMatch, lpY, cchY) != 0)
return FALSE;
}
else
{
if ((cchX + 1) > cchFileName)
return FALSE;
lpMatch = &lpFileName[cchX + 1];
}
/**
* State 3: final state
*/
*ppMatchEnd = &lpMatch[cchY];
return TRUE;
}
else if (*lpWildcard == '~')
{
WLog_ERR(TAG, "warning: unimplemented '~' pattern match");
return TRUE;
}
return FALSE;
}
BOOL FilePatternMatchA(LPCSTR lpFileName, LPCSTR lpPattern)
{
BOOL match = 0;
LPCSTR lpTail = nullptr;
size_t cchTail = 0;
size_t cchPattern = 0;
size_t cchFileName = 0;
DWORD dwFlags = 0;
DWORD dwNextFlags = 0;
LPSTR lpWildcard = nullptr;
LPSTR lpNextWildcard = nullptr;
/**
* Wild Card Matching
*
* '*' matches 0 or more characters
* '?' matches exactly one character
*
* '~*' DOS_STAR - matches 0 or more characters until encountering and matching final '.'
*
* '~?' DOS_QM - matches any single character, or upon encountering a period or end of name
* string, advances the expression to the end of the set of contiguous DOS_QMs.
*
* '~.' DOS_DOT - matches either a '.' or zero characters beyond name string.
*/
if (!lpPattern)
return FALSE;
if (!lpFileName)
return FALSE;
cchPattern = strlen(lpPattern);
cchFileName = strlen(lpFileName);
/**
* First and foremost the file system starts off name matching with the expression “*”.
* If the expression contains a single wild card character * all matches are satisfied
* immediately. This is the most common wild card character used in Windows and expression
* evaluation is optimized by looking for this character first.
*/
if ((lpPattern[0] == '*') && (cchPattern == 1))
return TRUE;
/**
* Subsequently evaluation of the “*X” expression is performed. This is a case where
* the expression starts off with a wild card character and contains some non-wild card
* characters towards the tail end of the name. This is evaluated by making sure the
* expression starts off with the character * and does not contain any wildcards in
* the latter part of the expression. The tail part of the expression beyond the first
* character * is matched against the file name at the end uppercasing each character
* if necessary during the comparison.
*/
if (lpPattern[0] == '*')
{
lpTail = &lpPattern[1];
cchTail = strlen(lpTail);
if (!FilePatternFindNextWildcardA(lpTail, &dwFlags))
{
/* tail contains no wildcards */
if (cchFileName < cchTail)
return FALSE;
if (_stricmp(&lpFileName[cchFileName - cchTail], lpTail) == 0)
return TRUE;
return FALSE;
}
}
/**
* The remaining expressions are evaluated in a non deterministic
* finite order as listed below, where:
*
* 'S' is any single character
* 'S-.' is any single character except the final '.'
* 'e' is a null character transition
* 'EOF' is the end of the name string
*
* S
* <-----<
* X | | e Y
* X * Y == (0)----->-(1)->-----(2)-----(3)
*
*
* S-.
* <-----<
* X | | e Y
* X ~* Y == (0)----->-(1)->-----(2)-----(3)
*
*
* X S S Y
* X ?? Y == (0)---(1)---(2)---(3)---(4)
*
*
* X S-. S-. Y
* X ~?~? == (0)---(1)-----(2)-----(3)---(4)
* | |_______|
* | ^ |
* |_______________|
* ^EOF of .^
*
*/
lpWildcard = FilePatternFindNextWildcardA(lpPattern, &dwFlags);
if (lpWildcard)
{
LPCSTR lpX = nullptr;
LPCSTR lpY = nullptr;
size_t cchX = 0;
size_t cchY = 0;
LPCSTR lpMatchEnd = nullptr;
LPCSTR lpSubPattern = nullptr;
size_t cchSubPattern = 0;
LPCSTR lpSubFileName = nullptr;
size_t cchSubFileName = 0;
size_t cchWildcard = 0;
size_t cchNextWildcard = 0;
cchSubPattern = cchPattern;
lpSubPattern = lpPattern;
cchSubFileName = cchFileName;
lpSubFileName = lpFileName;
cchWildcard = ((dwFlags & WILDCARD_DOS) ? 2 : 1);
lpNextWildcard = FilePatternFindNextWildcardA(&lpWildcard[cchWildcard], &dwNextFlags);
if (!lpNextWildcard)
{
lpX = lpSubPattern;
cchX = WINPR_ASSERTING_INT_CAST(size_t, (lpWildcard - lpSubPattern));
lpY = &lpSubPattern[cchX + cchWildcard];
cchY = (cchSubPattern - WINPR_ASSERTING_INT_CAST(size_t, (lpY - lpSubPattern)));
match = FilePatternMatchSubExpressionA(lpSubFileName, cchSubFileName, lpX, cchX, lpY,
cchY, lpWildcard, &lpMatchEnd);
return match;
}
else
{
while (lpNextWildcard)
{
cchSubFileName =
cchFileName - WINPR_ASSERTING_INT_CAST(size_t, (lpSubFileName - lpFileName));
cchNextWildcard = ((dwNextFlags & WILDCARD_DOS) ? 2 : 1);
lpX = lpSubPattern;
cchX = WINPR_ASSERTING_INT_CAST(size_t, (lpWildcard - lpSubPattern));
lpY = &lpSubPattern[cchX + cchWildcard];
cchY =
WINPR_ASSERTING_INT_CAST(size_t, (lpNextWildcard - lpWildcard)) - cchWildcard;
match = FilePatternMatchSubExpressionA(lpSubFileName, cchSubFileName, lpX, cchX,
lpY, cchY, lpWildcard, &lpMatchEnd);
if (!match)
return FALSE;
lpSubFileName = lpMatchEnd;
cchWildcard = cchNextWildcard;
lpWildcard = lpNextWildcard;
dwFlags = dwNextFlags;
lpNextWildcard =
FilePatternFindNextWildcardA(&lpWildcard[cchWildcard], &dwNextFlags);
}
return TRUE;
}
}
else
{
/* no wildcard characters */
if (_stricmp(lpFileName, lpPattern) == 0)
return TRUE;
}
return FALSE;
}

View File

@@ -0,0 +1,57 @@
if(NOT WIN32)
set(MODULE_NAME "TestFile")
set(MODULE_PREFIX "TEST_FILE")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS
TestFileCreateFile.c
TestFileDeleteFile.c
TestFileReadFile.c
TestSetFileAttributes.c
TestFileWriteFile.c
TestFilePatternMatch.c
TestFileFindFirstFile.c
TestFileFindFirstFileEx.c
TestFileFindNextFile.c
TestFileGetStdHandle.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}")
if(NOT MSVC)
set(TEST_AREA "${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME}Area")
else()
set(TEST_AREA "${TESTING_OUTPUT_DIRECTORY}/${CMAKE_BUILD_TYPE}/${MODULE_NAME}Area")
endif()
file(MAKE_DIRECTORY "${TEST_AREA}")
file(WRITE "${TEST_AREA}/TestFile1" "TestFile1")
file(WRITE "${TEST_AREA}/TestFile2" "TestFile2")
file(WRITE "${TEST_AREA}/TestFile3" "TestFile3")
file(MAKE_DIRECTORY "${TEST_AREA}/TestDirectory1")
file(WRITE "${TEST_AREA}/TestDirectory1/TestDirectory1File1" "TestDirectory1File1")
file(MAKE_DIRECTORY "${TEST_AREA}/TestDirectory2")
file(WRITE "${TEST_AREA}/TestDirectory2/TestDirectory2File1" "TestDirectory2File1")
file(WRITE "${TEST_AREA}/TestDirectory2/TestDirectory2File2" "TestDirectory2File2")
file(MAKE_DIRECTORY "${TEST_AREA}/TestDirectory3")
file(WRITE "${TEST_AREA}/TestDirectory3/TestDirectory3File1" "TestDirectory3File1")
file(WRITE "${TEST_AREA}/TestDirectory3/TestDirectory3File2" "TestDirectory3File2")
file(WRITE "${TEST_AREA}/TestDirectory3/TestDirectory3File3" "TestDirectory3File3")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName} ${TEST_AREA})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
endif()

View File

@@ -0,0 +1,94 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/file.h>
#include <winpr/path.h>
#include <winpr/handle.h>
#include <winpr/windows.h>
#include <winpr/sysinfo.h>
int TestFileCreateFile(int argc, char* argv[])
{
HANDLE handle = nullptr;
HRESULT hr = 0;
DWORD written = 0;
const char buffer[] = "Some random text\r\njust want it done.";
char cmp[sizeof(buffer)];
char sname[8192];
LPSTR name = nullptr;
int rc = 0;
SYSTEMTIME systemTime;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
GetSystemTime(&systemTime);
(void)sprintf_s(sname, sizeof(sname),
"CreateFile-%04" PRIu16 "%02" PRIu16 "%02" PRIu16 "%02" PRIu16 "%02" PRIu16
"%02" PRIu16 "%04" PRIu16,
systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour,
systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds);
name = GetKnownSubPath(KNOWN_PATH_TEMP, sname);
if (!name)
return -1;
/* On windows we would need '\\' or '/' as separator.
* 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, nullptr, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, nullptr);
if (!handle)
{
free(name);
return -1;
}
if (!winpr_PathFileExists(name))
rc = -1;
if (!WriteFile(handle, buffer, sizeof(buffer), &written, nullptr))
rc = -1;
if (written != sizeof(buffer))
rc = -1;
written = SetFilePointer(handle, 5, nullptr, FILE_BEGIN);
if (written != 5)
rc = -1;
written = SetFilePointer(handle, 0, nullptr, FILE_CURRENT);
if (written != 5)
rc = -1;
written = SetFilePointer(handle, -5, nullptr, FILE_CURRENT);
if (written != 0)
rc = -1;
if (!ReadFile(handle, cmp, sizeof(cmp), &written, nullptr))
rc = -1;
if (written != sizeof(cmp))
rc = -1;
if (memcmp(buffer, cmp, sizeof(buffer)) != 0)
rc = -1;
if (!CloseHandle(handle))
rc = -1;
if (!winpr_DeleteFile(name))
rc = -1;
if (winpr_PathFileExists(name))
rc = -1;
free(name);
return rc;
}

View File

@@ -0,0 +1,67 @@
#include <stdio.h>
#include <stdlib.h>
#include <winpr/crt.h>
#include <winpr/file.h>
#include <winpr/path.h>
#include <winpr/windows.h>
#if !defined(_WIN32)
#include <sys/stat.h>
#endif
static int secure_mkstemp(char* tmpname)
{
#if !defined(_WIN32)
const mode_t mask = umask(S_IRWXU);
#endif
int fd = mkstemp(tmpname);
#if !defined(_WIN32)
(void)umask(mask);
#endif
return fd;
}
int TestFileDeleteFile(int argc, char* argv[])
{
BOOL rc = FALSE;
int fd = 0;
char validA[] = "/tmp/valid-test-file-XXXXXX";
char validW[] = "/tmp/valid-test-file-XXXXXX";
WCHAR* validWW = nullptr;
const char invalidA[] = "/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
WCHAR invalidW[sizeof(invalidA)] = WINPR_C_ARRAY_INIT;
(void)ConvertUtf8NToWChar(invalidA, ARRAYSIZE(invalidA), invalidW, ARRAYSIZE(invalidW));
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
rc = winpr_DeleteFile(invalidA);
if (rc)
return -1;
rc = DeleteFileW(invalidW);
if (rc)
return -1;
fd = secure_mkstemp(validA);
if (fd < 0)
return -1;
rc = winpr_DeleteFile(validA);
if (!rc)
return -1;
fd = secure_mkstemp(validW);
if (fd < 0)
return -1;
validWW = ConvertUtf8NToWCharAlloc(validW, ARRAYSIZE(validW), nullptr);
if (validWW)
rc = DeleteFileW(validWW);
free(validWW);
if (!rc)
return -1;
return 0;
}

View File

@@ -0,0 +1,360 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/handle.h>
#include <winpr/file.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/collections.h>
#include <winpr/windows.h>
static const CHAR testFile1A[] = "TestFile1A";
static BOOL create_fileA(const char* FilePath)
{
HANDLE hdl = CreateFileA(FilePath, GENERIC_ALL, 0, nullptr, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, nullptr);
if (hdl == INVALID_HANDLE_VALUE)
return FALSE;
(void)CloseHandle(hdl);
return TRUE;
}
static BOOL create_fileW(const WCHAR* FilePath)
{
HANDLE hdl = CreateFileW(FilePath, GENERIC_ALL, 0, nullptr, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, nullptr);
if (hdl == INVALID_HANDLE_VALUE)
return FALSE;
(void)CloseHandle(hdl);
return TRUE;
}
static BOOL create_layout_files(size_t level, const char* BasePath, wArrayList* files)
{
for (size_t x = 0; x < 10; x++)
{
CHAR FilePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
strncpy(FilePath, BasePath, ARRAYSIZE(FilePath));
CHAR name[64] = WINPR_C_ARRAY_INIT;
(void)_snprintf(name, ARRAYSIZE(name), "%zd-TestFile%zd", level, x);
NativePathCchAppendA(FilePath, PATHCCH_MAX_CCH, name);
if (create_fileA(FilePath))
ArrayList_Append(files, FilePath);
}
return TRUE;
}
static BOOL create_layout_directories(size_t level, size_t max_level, const char* BasePath,
wArrayList* files)
{
if (level >= max_level)
return TRUE;
CHAR FilePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
strncpy(FilePath, BasePath, ARRAYSIZE(FilePath));
PathCchConvertStyleA(FilePath, ARRAYSIZE(FilePath), PATH_STYLE_NATIVE);
if (!winpr_PathMakePath(FilePath, nullptr))
return FALSE;
ArrayList_Append(files, FilePath);
if (!create_layout_files(level + 1, BasePath, files))
return FALSE;
for (size_t x = 0; x < 10; x++)
{
CHAR CurFilePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
strncpy(CurFilePath, FilePath, ARRAYSIZE(CurFilePath));
PathCchConvertStyleA(CurFilePath, ARRAYSIZE(CurFilePath), PATH_STYLE_NATIVE);
CHAR name[64] = WINPR_C_ARRAY_INIT;
(void)_snprintf(name, ARRAYSIZE(name), "%zd-TestPath%zd", level, x);
NativePathCchAppendA(CurFilePath, PATHCCH_MAX_CCH, name);
if (!create_layout_directories(level + 1, max_level, CurFilePath, files))
return FALSE;
}
return TRUE;
}
static BOOL create_layout(const char* BasePath, wArrayList* files)
{
CHAR BasePathNative[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
memcpy(BasePathNative, BasePath, sizeof(BasePathNative));
PathCchConvertStyleA(BasePathNative, ARRAYSIZE(BasePathNative), PATH_STYLE_NATIVE);
return create_layout_directories(0, 3, BasePathNative, files);
}
static void cleanup_layout(const char* BasePath)
{
winpr_RemoveDirectory_RecursiveA(BasePath);
}
static BOOL find_first_file_success(const char* FilePath)
{
BOOL rc = FALSE;
WIN32_FIND_DATAA FindData = WINPR_C_ARRAY_INIT;
HANDLE hFind = FindFirstFileA(FilePath, &FindData);
if (hFind == INVALID_HANDLE_VALUE)
{
printf("FindFirstFile failure: %s (INVALID_HANDLE_VALUE -1)\n", FilePath);
goto fail;
}
printf("FindFirstFile: %s\n", FindData.cFileName);
if (strcmp(FindData.cFileName, testFile1A) != 0)
{
printf("FindFirstFile failure: Expected: %s, Actual: %s\n", testFile1A, FindData.cFileName);
goto fail;
}
rc = TRUE;
fail:
if (hFind != INVALID_HANDLE_VALUE)
FindClose(hFind);
return rc;
}
static BOOL list_directory_dot(const char* BasePath, wArrayList* files)
{
BOOL rc = FALSE;
CHAR BasePathDot[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
memcpy(BasePathDot, BasePath, ARRAYSIZE(BasePathDot));
PathCchConvertStyleA(BasePathDot, ARRAYSIZE(BasePathDot), PATH_STYLE_NATIVE);
NativePathCchAppendA(BasePathDot, PATHCCH_MAX_CCH, ".");
WIN32_FIND_DATAA FindData = WINPR_C_ARRAY_INIT;
HANDLE hFind = FindFirstFileA(BasePathDot, &FindData);
if (hFind == INVALID_HANDLE_VALUE)
return FALSE;
size_t count = 0;
do
{
count++;
if (strcmp(FindData.cFileName, ".") != 0)
goto fail;
} while (FindNextFile(hFind, &FindData));
rc = TRUE;
fail:
FindClose(hFind);
if (count != 1)
return FALSE;
return rc;
}
static BOOL list_directory_star(const char* BasePath, wArrayList* files)
{
CHAR BasePathDot[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
memcpy(BasePathDot, BasePath, ARRAYSIZE(BasePathDot));
PathCchConvertStyleA(BasePathDot, ARRAYSIZE(BasePathDot), PATH_STYLE_NATIVE);
NativePathCchAppendA(BasePathDot, PATHCCH_MAX_CCH, "*");
WIN32_FIND_DATAA FindData = WINPR_C_ARRAY_INIT;
HANDLE hFind = FindFirstFileA(BasePathDot, &FindData);
if (hFind == INVALID_HANDLE_VALUE)
return FALSE;
size_t count = 0;
size_t dotcount = 0;
size_t dotdotcount = 0;
do
{
if (strcmp(FindData.cFileName, ".") == 0)
dotcount++;
else if (strcmp(FindData.cFileName, "..") == 0)
dotdotcount++;
else
count++;
} while (FindNextFile(hFind, &FindData));
FindClose(hFind);
const char sep = PathGetSeparatorA(PATH_STYLE_NATIVE);
size_t fcount = 0;
const size_t baselen = strlen(BasePath);
const size_t total = ArrayList_Count(files);
for (size_t x = 0; x < total; x++)
{
const char* path = ArrayList_GetItem(files, x);
const size_t pathlen = strlen(path);
if (pathlen < baselen)
continue;
const char* skip = &path[baselen];
if (*skip == sep)
skip++;
const char* end = strrchr(skip, sep);
if (end)
continue;
fcount++;
}
return (fcount == count);
}
static BOOL find_first_file_fail(const char* FilePath)
{
WIN32_FIND_DATAA FindData = WINPR_C_ARRAY_INIT;
HANDLE hFind = FindFirstFileA(FilePath, &FindData);
if (hFind == INVALID_HANDLE_VALUE)
return TRUE;
FindClose(hFind);
return FALSE;
}
static int TestFileFindFirstFileA(const char* str)
{
int rc = -1;
printf("[%s] basepath: '%s'\n", __func__, str);
if (!str)
return -1;
CHAR BasePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
strncpy(BasePath, str, ARRAYSIZE(BasePath));
const size_t length = strnlen(BasePath, PATHCCH_MAX_CCH - 1);
CHAR FilePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
CopyMemory(FilePath, BasePath, length * sizeof(CHAR));
PathCchConvertStyleA(BasePath, length, PATH_STYLE_WINDOWS);
wArrayList* files = ArrayList_New(FALSE);
if (!files)
return -3;
wObject* obj = ArrayList_Object(files);
obj->fnObjectFree = winpr_ObjectStringFree;
obj->fnObjectNew = winpr_ObjectStringClone;
if (!create_layout(BasePath, files))
goto fail;
NativePathCchAppendA(FilePath, PATHCCH_MAX_CCH, testFile1A);
printf("Finding file: %s\n", FilePath);
if (!find_first_file_fail(FilePath))
goto fail;
if (!create_fileA(FilePath))
goto fail;
if (!find_first_file_success(FilePath))
goto fail;
CHAR BasePathInvalid[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
memcpy(BasePathInvalid, BasePath, ARRAYSIZE(BasePathInvalid));
PathCchAddBackslashA(BasePathInvalid, PATHCCH_MAX_CCH);
if (!find_first_file_fail(BasePathInvalid))
goto fail;
if (!list_directory_dot(BasePath, files))
goto fail;
if (!list_directory_star(BasePath, files))
goto fail;
rc = 0;
fail:
winpr_DeleteFile(FilePath);
cleanup_layout(BasePath);
ArrayList_Free(files);
return rc;
}
WINPR_ATTR_FORMAT_ARG(1, 0)
static int printf1W(const char* WINPR_FORMAT_ARG fmt, const WCHAR* arg1)
{
char* var1 = ConvertWCharToUtf8Alloc(arg1, nullptr);
const int rc = printf(fmt, var1);
free(var1);
return rc;
}
WINPR_ATTR_FORMAT_ARG(1, 0)
static int printf2W(const char* WINPR_FORMAT_ARG fmt, const WCHAR* arg1, const WCHAR* arg2)
{
char* var1 = ConvertWCharToUtf8Alloc(arg1, nullptr);
char* var2 = ConvertWCharToUtf8Alloc(arg2, nullptr);
const int rc = printf(fmt, var1, var2);
free(var1);
free(var2);
return rc;
}
static int TestFileFindFirstFileW(const char* str)
{
WCHAR buffer[32] = WINPR_C_ARRAY_INIT;
const WCHAR* testFile1W = InitializeConstWCharFromUtf8("TestFile1W", buffer, ARRAYSIZE(buffer));
int rc = -1;
if (!str)
return -1;
WCHAR BasePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
printf("[%s] basepath: '%s'\n", __func__, str);
(void)ConvertUtf8ToWChar(str, BasePath, ARRAYSIZE(BasePath));
const size_t length = _wcsnlen(BasePath, PATHCCH_MAX_CCH - 1);
WCHAR FilePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
CopyMemory(FilePath, BasePath, length * sizeof(WCHAR));
PathCchConvertStyleW(BasePath, length, PATH_STYLE_WINDOWS);
NativePathCchAppendW(FilePath, PATHCCH_MAX_CCH, testFile1W);
HANDLE hFind = INVALID_HANDLE_VALUE;
if (!create_fileW(FilePath))
goto fail;
printf1W("Finding file: %s\n", FilePath);
WIN32_FIND_DATAW FindData = WINPR_C_ARRAY_INIT;
hFind = FindFirstFileW(FilePath, &FindData);
if (hFind == INVALID_HANDLE_VALUE)
{
printf1W("FindFirstFile failure: %s (INVALID_HANDLE_VALUE -1)\n", FilePath);
goto fail;
}
printf1W("FindFirstFile: %s\n", FindData.cFileName);
if (_wcscmp(FindData.cFileName, testFile1W) != 0)
{
printf2W("FindFirstFile failure: Expected: %s, Actual: %s\n", testFile1W,
FindData.cFileName);
goto fail;
}
rc = 0;
fail:
DeleteFileW(FilePath);
FindClose(hFind);
return rc;
}
int TestFileFindFirstFile(int argc, char* argv[])
{
char* str = GetKnownSubPath(KNOWN_PATH_TEMP, "TestFileFindFirstFile");
if (!str)
return -23;
cleanup_layout(str);
int rc1 = -1;
int rc2 = -1;
if (winpr_PathMakePath(str, nullptr))
{
rc1 = TestFileFindFirstFileA(str);
rc2 = TestFileFindFirstFileW(str);
winpr_RemoveDirectory(str);
}
free(str);
return rc1 + rc2;
}

View File

@@ -0,0 +1,10 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/file.h>
#include <winpr/windows.h>
int TestFileFindFirstFileEx(int argc, char* argv[])
{
return 0;
}

View File

@@ -0,0 +1,99 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/file.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/windows.h>
static TCHAR testDirectory2File1[] = _T("TestDirectory2File1");
static TCHAR testDirectory2File2[] = _T("TestDirectory2File2");
int TestFileFindNextFile(int argc, char* argv[])
{
char* str = nullptr;
size_t length = 0;
BOOL status = 0;
HANDLE hFind = nullptr;
LPTSTR BasePath = nullptr;
WIN32_FIND_DATA FindData;
TCHAR FilePath[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
WINPR_UNUSED(argc);
str = argv[1];
#ifdef UNICODE
BasePath = ConvertUtf8ToWChar(str, &length);
if (!BasePath)
{
_tprintf(_T("Unable to allocate memory"));
return -1;
}
#else
BasePath = _strdup(str);
if (!BasePath)
{
printf("Unable to allocate memory");
return -1;
}
length = strlen(BasePath);
#endif
/* Simple filter matching all files inside current directory */
CopyMemory(FilePath, BasePath, length * sizeof(TCHAR));
FilePath[length] = 0;
PathCchConvertStyle(BasePath, length, PATH_STYLE_WINDOWS);
NativePathCchAppend(FilePath, PATHCCH_MAX_CCH, _T("TestDirectory2"));
NativePathCchAppend(FilePath, PATHCCH_MAX_CCH, _T("TestDirectory2File*"));
free(BasePath);
_tprintf(_T("Finding file: %s\n"), FilePath);
hFind = FindFirstFile(FilePath, &FindData);
if (hFind == INVALID_HANDLE_VALUE)
{
_tprintf(_T("FindFirstFile failure: %s\n"), FilePath);
return -1;
}
_tprintf(_T("FindFirstFile: %s"), FindData.cFileName);
/**
* The current implementation does not enforce a particular order
*/
if ((_tcsncmp(FindData.cFileName, testDirectory2File1, ARRAYSIZE(testDirectory2File1)) != 0) &&
(_tcsncmp(FindData.cFileName, testDirectory2File2, ARRAYSIZE(testDirectory2File2)) != 0))
{
_tprintf(_T("FindFirstFile failure: Expected: %s, Actual: %s\n"), testDirectory2File1,
FindData.cFileName);
return -1;
}
status = FindNextFile(hFind, &FindData);
if (!status)
{
_tprintf(_T("FindNextFile failure: Expected: TRUE, Actual: %") _T(PRId32) _T("\n"), status);
return -1;
}
if ((_tcsncmp(FindData.cFileName, testDirectory2File1, ARRAYSIZE(testDirectory2File1)) != 0) &&
(_tcsncmp(FindData.cFileName, testDirectory2File2, ARRAYSIZE(testDirectory2File2)) != 0))
{
_tprintf(_T("FindNextFile failure: Expected: %s, Actual: %s\n"), testDirectory2File2,
FindData.cFileName);
return -1;
}
status = FindNextFile(hFind, &FindData);
if (status)
{
_tprintf(_T("FindNextFile failure: Expected: FALSE, Actual: %") _T(PRId32) _T("\n"),
status);
return -1;
}
FindClose(hFind);
return 0;
}

View File

@@ -0,0 +1,49 @@
/**
* WinPR: Windows Portable Runtime
* File Functions
*
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 Bernhard Miklautz <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.
*/
#include <winpr/file.h>
#include <winpr/handle.h>
#include <string.h>
#include <stdio.h>
int TestFileGetStdHandle(int argc, char* argv[])
{
HANDLE so = nullptr;
const char buf[] = "happy happy";
DWORD bytesWritten = 0;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
so = GetStdHandle(STD_OUTPUT_HANDLE);
if (so == INVALID_HANDLE_VALUE)
{
(void)fprintf(stderr, "GetStdHandle failed ;(\n");
return -1;
}
WriteFile(so, buf, strnlen(buf, sizeof(buf)), &bytesWritten, nullptr);
if (bytesWritten != strnlen(buf, sizeof(buf)))
{
(void)fprintf(stderr, "write failed\n");
return -1;
}
(void)CloseHandle(so);
return 0;
}

View File

@@ -0,0 +1,182 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/file.h>
#include <winpr/windows.h>
int TestFilePatternMatch(int argc, char* argv[])
{
/* '*' expression */
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (!FilePatternMatchA("document.txt", "*"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "document.txt", "*");
return -1;
}
/* '*X' expression */
if (!FilePatternMatchA("document.txt", "*.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "document.txt", "*.txt");
return -1;
}
if (FilePatternMatchA("document.docx", "*.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "document.docx", "*.txt");
return -1;
}
if (FilePatternMatchA("document.txt.bak", "*.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "document.txt.bak", "*.txt");
return -1;
}
if (FilePatternMatchA("bak", "*.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "bak", "*.txt");
return -1;
}
/* 'X*' expression */
if (!FilePatternMatchA("document.txt", "document.*"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "document.txt", "document.*");
return -1;
}
/* 'X?' expression */
if (!FilePatternMatchA("document.docx", "document.doc?"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "document.docx",
"document.doc?");
return -1;
}
if (FilePatternMatchA("document.doc", "document.doc?"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "document.doc",
"document.doc?");
return -1;
}
/* no wildcards expression */
if (!FilePatternMatchA("document.txt", "document.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "document.txt",
"document.txt");
return -1;
}
/* 'X * Y' expression */
if (!FilePatternMatchA("X123Y.txt", "X*Y.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "X123Y.txt", "X*Y.txt");
return -1;
}
if (!FilePatternMatchA("XY.txt", "X*Y.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "XY.txt", "X*Y.txt");
return -1;
}
if (FilePatternMatchA("XZ.txt", "X*Y.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "XZ.txt", "X*Y.txt");
return -1;
}
if (FilePatternMatchA("X123Z.txt", "X*Y.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "X123Z.txt", "X*Y.txt");
return -1;
}
/* 'X * Y * Z' expression */
if (!FilePatternMatchA("X123Y456Z.txt", "X*Y*Z.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "X123Y456Z.txt", "X*Y*Z.txt");
return -1;
}
if (!FilePatternMatchA("XYZ.txt", "X*Y*Z.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "XYZ.txt", "X*Y*Z.txt");
return -1;
}
if (!FilePatternMatchA("X123Y456W.txt", "X*Y*Z.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "X123Y456W.txt", "X*Y*Z.txt");
return -1;
}
if (!FilePatternMatchA("XYW.txt", "X*Y*Z.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "XYW.txt", "X*Y*Z.txt");
return -1;
}
/* 'X ? Y' expression */
if (!FilePatternMatchA("X1Y.txt", "X?Y.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "X1Y.txt", "X?Y.txt");
return -1;
}
if (FilePatternMatchA("XY.txt", "X?Y.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "XY.txt", "X?Y.txt");
return -1;
}
if (FilePatternMatchA("XZ.txt", "X?Y.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "XZ.txt", "X?Y.txt");
return -1;
}
if (FilePatternMatchA("X123Z.txt", "X?Y.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "X123Z.txt", "X?Y.txt");
return -1;
}
/* 'X ? Y ? Z' expression */
if (!FilePatternMatchA("X123Y456Z.txt", "X?Y?Z.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "X123Y456Z.txt", "X?Y?Z.txt");
return -1;
}
if (FilePatternMatchA("XYZ.txt", "X?Y?Z.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "XYZ.txt", "X?Y?Z.txt");
return -1;
}
if (!FilePatternMatchA("X123Y456W.txt", "X?Y?Z.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "X123Y456W.txt", "X?Y?Z.txt");
return -1;
}
if (FilePatternMatchA("XYW.txt", "X?Y?Z.txt"))
{
printf("FilePatternMatchA error: FileName: %s Pattern: %s\n", "XYW.txt", "X?Y?Z.txt");
return -1;
}
return 0;
}

View File

@@ -0,0 +1,10 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/file.h>
#include <winpr/windows.h>
int TestFileReadFile(int argc, char* argv[])
{
return 0;
}

View File

@@ -0,0 +1,128 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/file.h>
#include <winpr/windows.h>
static const char* get_dir(char* filename, size_t len)
{
#if defined(WIN32)
if ((len == 0) || (strnlen_s(filename, len) == len))
return nullptr;
char* ptr = strrchr(filename, '\\');
#else
if ((len == 0) || (strnlen(filename, len) == len))
return nullptr;
char* ptr = strrchr(filename, '/');
#endif
if (!ptr)
return nullptr;
*ptr = '\0';
return filename;
}
static BOOL get_tmp(char* path, size_t len)
{
#if defined(WIN32)
const char template[] = "tmpdir.XXXXXX";
strncmp(path, template, strnlen_s(template, len) + 1);
if (!mktemp_s(path))
return FALSE;
return winpr_str_append("testfile", path, len, "\\");
#else
const char template[] = "/tmp/tmpdir.XXXXXX";
if (!strncpy(path, template, strnlen(template, len) + 1))
return FALSE;
if (!mkdtemp(path))
return FALSE;
return winpr_str_append("testfile", path, len, "/");
#endif
}
static BOOL test_write(const char* filename, const char* data, size_t datalen)
{
BOOL rc = FALSE;
WINPR_ASSERT(filename);
WINPR_ASSERT(data);
WINPR_ASSERT(datalen > 0);
HANDLE hdl = CreateFileA(filename, GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL,
nullptr);
if (!hdl || (hdl == INVALID_HANDLE_VALUE))
goto fail;
DWORD written = 0;
if (!WriteFile(hdl, data, datalen, &written, nullptr))
goto fail;
if (written != datalen)
goto fail;
if (!FlushFileBuffers(hdl))
goto fail;
rc = TRUE;
fail:
CloseHandle(hdl);
return rc;
}
static BOOL test_read(const char* filename, const char* data, size_t datalen)
{
BOOL rc = FALSE;
WINPR_ASSERT(filename);
WINPR_ASSERT(data);
WINPR_ASSERT(datalen > 0);
char* cmp = calloc(datalen + 1, sizeof(char));
HANDLE hdl = CreateFileA(filename, GENERIC_READ, 0, nullptr, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, nullptr);
if (!hdl || (hdl == INVALID_HANDLE_VALUE) || !cmp)
goto fail;
DWORD read = 0;
if (!ReadFile(hdl, cmp, datalen, &read, nullptr))
goto fail;
if (read != datalen)
goto fail;
if (memcmp(data, cmp, datalen) != 0)
goto fail;
if (FlushFileBuffers(hdl))
goto fail;
rc = TRUE;
fail:
free(cmp);
CloseHandle(hdl);
return rc;
}
int TestFileWriteFile(int argc, char* argv[])
{
const char data[] = "sometesttext\nanother line\r\ngogogo\r\tfoo\t\r\n\r";
char filename[MAX_PATH] = WINPR_C_ARRAY_INIT;
int rc = -1;
if (!get_tmp(filename, sizeof(filename)))
goto fail;
if (!test_write(filename, data, sizeof(data)))
goto fail;
if (!test_read(filename, data, sizeof(data)))
goto fail;
rc = 0;
fail:
if (!DeleteFile(filename))
rc = -2;
const char* d = get_dir(filename, sizeof(filename));
if (d)
{
if (!RemoveDirectory(d))
rc = -3;
}
return rc;
}

View File

@@ -0,0 +1,152 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/file.h>
#include <winpr/path.h>
#include <winpr/handle.h>
#include <winpr/windows.h>
#include <winpr/sysinfo.h>
static const DWORD allflags[] = {
0,
FILE_ATTRIBUTE_READONLY,
FILE_ATTRIBUTE_HIDDEN,
FILE_ATTRIBUTE_SYSTEM,
FILE_ATTRIBUTE_DIRECTORY,
FILE_ATTRIBUTE_ARCHIVE,
FILE_ATTRIBUTE_DEVICE,
FILE_ATTRIBUTE_NORMAL,
FILE_ATTRIBUTE_TEMPORARY,
FILE_ATTRIBUTE_SPARSE_FILE,
FILE_ATTRIBUTE_REPARSE_POINT,
FILE_ATTRIBUTE_COMPRESSED,
FILE_ATTRIBUTE_OFFLINE,
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
FILE_ATTRIBUTE_ENCRYPTED,
FILE_ATTRIBUTE_VIRTUAL,
FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE |
FILE_ATTRIBUTE_NORMAL,
FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_SPARSE_FILE | FILE_ATTRIBUTE_REPARSE_POINT |
FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_OFFLINE,
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_VIRTUAL
};
static BOOL test_SetFileAttributesA(void)
{
BOOL rc = FALSE;
HANDLE handle = nullptr;
const DWORD flags[] = { 0, FILE_ATTRIBUTE_READONLY };
char* name = GetKnownSubPath(KNOWN_PATH_TEMP, "afsklhjwe4oq5iu432oijrlkejadlkhjaklhfdkahfd");
if (!name)
goto fail;
for (size_t x = 0; x < ARRAYSIZE(allflags); x++)
{
const DWORD flag = allflags[x];
const BOOL brc = SetFileAttributesA(nullptr, flag);
if (brc)
goto fail;
const BOOL crc = SetFileAttributesA(name, flag);
if (crc)
goto fail;
}
handle = CreateFileA(name, GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, nullptr);
if (handle == INVALID_HANDLE_VALUE)
goto fail;
(void)CloseHandle(handle);
for (size_t x = 0; x < ARRAYSIZE(flags); x++)
{
DWORD attr = 0;
const DWORD flag = flags[x];
const BOOL brc = SetFileAttributesA(name, flag);
if (!brc)
goto fail;
attr = GetFileAttributesA(name);
if (flag != 0)
{
if ((attr & flag) == 0)
goto fail;
}
}
rc = TRUE;
fail:
winpr_DeleteFile(name);
free(name);
return rc;
}
static BOOL test_SetFileAttributesW(void)
{
BOOL rc = FALSE;
WCHAR* name = nullptr;
HANDLE handle = nullptr;
const DWORD flags[] = { 0, FILE_ATTRIBUTE_READONLY };
char* base = GetKnownSubPath(KNOWN_PATH_TEMP, "afsklhjwe4oq5iu432oijrlkejadlkhjaklhfdkahfd");
if (!base)
goto fail;
name = ConvertUtf8ToWCharAlloc(base, nullptr);
if (!name)
goto fail;
for (size_t x = 0; x < ARRAYSIZE(allflags); x++)
{
const DWORD flag = allflags[x];
const BOOL brc = SetFileAttributesW(nullptr, flag);
if (brc)
goto fail;
const BOOL crc = SetFileAttributesW(name, flag);
if (crc)
goto fail;
}
handle = CreateFileW(name, GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, nullptr);
if (handle == INVALID_HANDLE_VALUE)
goto fail;
(void)CloseHandle(handle);
for (size_t x = 0; x < ARRAYSIZE(flags); x++)
{
DWORD attr = 0;
const DWORD flag = flags[x];
const BOOL brc = SetFileAttributesW(name, flag);
if (!brc)
goto fail;
attr = GetFileAttributesW(name);
if (flag != 0)
{
if ((attr & flag) == 0)
goto fail;
}
}
rc = TRUE;
fail:
DeleteFileW(name);
free(name);
free(base);
return rc;
}
int TestSetFileAttributes(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (!test_SetFileAttributesA())
return -1;
if (!test_SetFileAttributesW())
return -1;
return 0;
}