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,30 @@
# WinPR: Windows Portable Runtime
# libwinpr-path 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(path.c shell.c)
if(MSVC OR MINGW)
winpr_library_add_public(shlwapi)
endif()
if(IOS)
winpr_module_add(shell_ios.m)
endif(IOS)
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 "1")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "path")
set(MINWIN_LONG_NAME "Path Functions")
set(MODULE_LIBRARY_NAME
"api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}"
)

View File

@@ -0,0 +1,174 @@
/*
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR '\\'
#define CUR_PATH_SEPARATOR_STR "\\"
#define PATH_ALLOC_COMBINE PathAllocCombineA
*/
/**
* FIXME: These implementations of the PathAllocCombine functions have
* several issues:
* - pszPathIn or pszMore may be nullptr (but not both)
* - no check if pszMore is fully qualified (if so, it must be directly
* copied to the output buffer without being combined with pszPathIn.
* - if pszMore begins with a _single_ backslash it must be combined with
* only the root of the path pointed to by pszPathIn and there's no code
* to extract the root of pszPathIn.
* - the function will crash with some short string lengths of the parameters
*/
#include <stdlib.h>
#include <string.h>
#include <winpr/wtypes.h>
#include <winpr/string.h>
#include <winpr/error.h>
#include <winpr/wlog.h>
#if DEFINE_UNICODE
HRESULT PATH_ALLOC_COMBINE(PCWSTR pszPathIn, PCWSTR pszMore,
WINPR_ATTR_UNUSED unsigned long dwFlags, PWSTR* ppszPathOut)
{
WLog_WARN("TODO", "has known bugs and needs fixing.");
if (!ppszPathOut)
return E_INVALIDARG;
if (!pszPathIn && !pszMore)
return E_INVALIDARG;
if (!pszMore)
return E_FAIL; /* valid but not implemented, see top comment */
if (!pszPathIn)
return E_FAIL; /* valid but not implemented, see top comment */
const size_t pszPathInLength = _wcslen(pszPathIn);
const size_t pszMoreLength = _wcslen(pszMore);
/* prevent segfaults - the complete implementation below is buggy */
if (pszPathInLength < 3)
return E_FAIL;
const BOOL backslashIn =
(pszPathIn[pszPathInLength - 1] == CUR_PATH_SEPARATOR_CHR) ? TRUE : FALSE;
const BOOL backslashMore = (pszMore[0] == CUR_PATH_SEPARATOR_CHR) ? TRUE : FALSE;
if (backslashMore)
{
if ((pszPathIn[1] == ':') && (pszPathIn[2] == CUR_PATH_SEPARATOR_CHR))
{
const WCHAR colon[] = { ':', '\0' };
const size_t pszPathOutLength = sizeof(WCHAR) + pszMoreLength;
const size_t sizeOfBuffer = (pszPathOutLength + 1) * sizeof(WCHAR);
PWSTR pszPathOut = (PWSTR)calloc(sizeOfBuffer, sizeof(WCHAR));
if (!pszPathOut)
return E_OUTOFMEMORY;
_wcsncat(pszPathOut, &pszPathIn[0], 1);
_wcsncat(pszPathOut, colon, ARRAYSIZE(colon));
_wcsncat(pszPathOut, pszMore, pszMoreLength);
*ppszPathOut = pszPathOut;
return S_OK;
}
}
else
{
const size_t pszPathOutLength = pszPathInLength + pszMoreLength;
const size_t sizeOfBuffer = (pszPathOutLength + 1) * sizeof(WCHAR);
PWSTR pszPathOut = (PWSTR)calloc(sizeOfBuffer, 2);
if (!pszPathOut)
return E_OUTOFMEMORY;
_wcsncat(pszPathOut, pszPathIn, pszPathInLength);
if (!backslashIn)
_wcsncat(pszPathOut, CUR_PATH_SEPARATOR_STR, ARRAYSIZE(CUR_PATH_SEPARATOR_STR));
_wcsncat(pszPathOut, pszMore, pszMoreLength);
*ppszPathOut = pszPathOut;
return S_OK;
}
return E_FAIL;
}
#else
HRESULT PATH_ALLOC_COMBINE(PCSTR pszPathIn, PCSTR pszMore, WINPR_ATTR_UNUSED unsigned long dwFlags,
PSTR* ppszPathOut)
{
WLog_WARN("TODO", "has known bugs and needs fixing.");
if (!ppszPathOut)
return E_INVALIDARG;
if (!pszPathIn && !pszMore)
return E_INVALIDARG;
if (!pszMore)
return E_FAIL; /* valid but not implemented, see top comment */
if (!pszPathIn)
return E_FAIL; /* valid but not implemented, see top comment */
const size_t pszPathInLength = strlen(pszPathIn);
const size_t pszMoreLength = strlen(pszMore);
/* prevent segfaults - the complete implementation below is buggy */
if (pszPathInLength < 3)
return E_FAIL;
const BOOL backslashIn =
(pszPathIn[pszPathInLength - 1] == CUR_PATH_SEPARATOR_CHR) ? TRUE : FALSE;
const BOOL backslashMore = (pszMore[0] == CUR_PATH_SEPARATOR_CHR) ? TRUE : FALSE;
if (backslashMore)
{
if ((pszPathIn[1] == ':') && (pszPathIn[2] == CUR_PATH_SEPARATOR_CHR))
{
const size_t pszPathOutLength = 2 + pszMoreLength;
const size_t sizeOfBuffer = (pszPathOutLength + 1) * sizeof(WCHAR);
PSTR pszPathOut = calloc(sizeOfBuffer, 2);
if (!pszPathOut)
return E_OUTOFMEMORY;
(void)sprintf_s(pszPathOut, sizeOfBuffer, "%c:%s", pszPathIn[0], pszMore);
*ppszPathOut = pszPathOut;
return S_OK;
}
}
else
{
const size_t pszPathOutLength = pszPathInLength + pszMoreLength;
const size_t sizeOfBuffer = (pszPathOutLength + 1) * sizeof(WCHAR);
PSTR pszPathOut = calloc(sizeOfBuffer, 2);
if (!pszPathOut)
return E_OUTOFMEMORY;
if (backslashIn)
(void)sprintf_s(pszPathOut, sizeOfBuffer, "%s%s", pszPathIn, pszMore);
else
(void)sprintf_s(pszPathOut, sizeOfBuffer, "%s%s%s", pszPathIn, CUR_PATH_SEPARATOR_STR,
pszMore);
*ppszPathOut = pszPathOut;
return S_OK;
}
return E_FAIL;
}
#endif
/*
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef CUR_PATH_SEPARATOR_STR
#undef PATH_ALLOC_COMBINE
*/

View File

@@ -0,0 +1,101 @@
/*
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR '\\'
#define PATH_CCH_ADD_EXTENSION PathCchAddExtensionA
*/
#if DEFINE_UNICODE
HRESULT PATH_CCH_ADD_EXTENSION(PWSTR pszPath, size_t cchPath, PCWSTR pszExt)
{
LPWSTR pDot;
BOOL bExtDot;
LPWSTR pBackslash;
size_t pszExtLength;
size_t pszPathLength;
if (!pszPath)
return E_INVALIDARG;
if (!pszExt)
return E_INVALIDARG;
pszExtLength = _wcslen(pszExt);
pszPathLength = _wcslen(pszPath);
bExtDot = (pszExt[0] == '.') ? TRUE : FALSE;
pDot = _wcsrchr(pszPath, '.');
pBackslash = _wcsrchr(pszPath, CUR_PATH_SEPARATOR_CHR);
if (pDot && pBackslash)
{
if (pDot > pBackslash)
return S_FALSE;
}
if (cchPath > pszPathLength + pszExtLength + ((bExtDot) ? 0 : 1))
{
const WCHAR dot[] = { '.', '\0' };
WCHAR* ptr = &pszPath[pszPathLength];
*ptr = '\0';
if (!bExtDot)
_wcsncat(ptr, dot, _wcslen(dot));
_wcsncat(ptr, pszExt, pszExtLength);
return S_OK;
}
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
#else
HRESULT PATH_CCH_ADD_EXTENSION(PSTR pszPath, size_t cchPath, PCSTR pszExt)
{
CHAR* pDot;
BOOL bExtDot;
CHAR* pBackslash;
size_t pszExtLength;
size_t pszPathLength;
if (!pszPath)
return E_INVALIDARG;
if (!pszExt)
return E_INVALIDARG;
pszExtLength = strlen(pszExt);
pszPathLength = strlen(pszPath);
bExtDot = (pszExt[0] == '.') ? TRUE : FALSE;
pDot = strrchr(pszPath, '.');
pBackslash = strrchr(pszPath, CUR_PATH_SEPARATOR_CHR);
if (pDot && pBackslash)
{
if (pDot > pBackslash)
return S_FALSE;
}
if (cchPath > pszPathLength + pszExtLength + ((bExtDot) ? 0 : 1))
{
if (bExtDot)
sprintf_s(&pszPath[pszPathLength], cchPath - pszPathLength, "%s", pszExt);
else
sprintf_s(&pszPath[pszPathLength], cchPath - pszPathLength, ".%s", pszExt);
return S_OK;
}
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
#endif
/*
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_EXTENSION
*/

View File

@@ -0,0 +1,64 @@
/*
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR '\\'
#define PATH_CCH_ADD_SEPARATOR PathCchAddBackslashA
*/
#if DEFINE_UNICODE
HRESULT PATH_CCH_ADD_SEPARATOR(PWSTR pszPath, size_t cchPath)
{
size_t pszPathLength;
if (!pszPath)
return E_INVALIDARG;
pszPathLength = _wcslen(pszPath);
if (pszPath[pszPathLength - 1] == CUR_PATH_SEPARATOR_CHR)
return S_FALSE;
if (cchPath > (pszPathLength + 1))
{
pszPath[pszPathLength] = CUR_PATH_SEPARATOR_CHR;
pszPath[pszPathLength + 1] = '\0';
return S_OK;
}
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
#else
HRESULT PATH_CCH_ADD_SEPARATOR(PSTR pszPath, size_t cchPath)
{
size_t pszPathLength;
if (!pszPath)
return E_INVALIDARG;
pszPathLength = strlen(pszPath);
if (pszPath[pszPathLength - 1] == CUR_PATH_SEPARATOR_CHR)
return S_FALSE;
if (cchPath > (pszPathLength + 1))
{
pszPath[pszPathLength] = CUR_PATH_SEPARATOR_CHR;
pszPath[pszPathLength + 1] = '\0';
return S_OK;
}
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
#endif
/*
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_SEPARATOR
*/

View File

@@ -0,0 +1,69 @@
#include <winpr/wtypes.h>
/*
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR '\\'
#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddBackslashExA
*/
#if DEFINE_UNICODE
HRESULT PATH_CCH_ADD_SEPARATOR_EX(PWSTR pszPath, size_t cchPath, WINPR_ATTR_UNUSED PWSTR* ppszEnd,
WINPR_ATTR_UNUSED size_t* pcchRemaining)
{
size_t pszPathLength;
if (!pszPath)
return E_INVALIDARG;
pszPathLength = _wcslen(pszPath);
if (pszPath[pszPathLength - 1] == CUR_PATH_SEPARATOR_CHR)
return S_FALSE;
if (cchPath > (pszPathLength + 1))
{
pszPath[pszPathLength] = CUR_PATH_SEPARATOR_CHR;
pszPath[pszPathLength + 1] = '\0';
return S_OK;
}
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
#else
HRESULT PATH_CCH_ADD_SEPARATOR_EX(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
WINPR_ATTR_UNUSED PSTR* ppszEnd,
WINPR_ATTR_UNUSED size_t* pcchRemaining)
{
size_t pszPathLength;
if (!pszPath)
return E_INVALIDARG;
pszPathLength = strlen(pszPath);
if (pszPath[pszPathLength - 1] == CUR_PATH_SEPARATOR_CHR)
return S_FALSE;
if (cchPath > (pszPathLength + 1))
{
pszPath[pszPathLength] = CUR_PATH_SEPARATOR_CHR;
pszPath[pszPathLength + 1] = '\0';
return S_OK;
}
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
#endif
/*
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_SEPARATOR_EX
*/

View File

@@ -0,0 +1,136 @@
/*
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR '\\'
#define CUR_PATH_SEPARATOR_STR "\\"
#define PATH_CCH_APPEND PathCchAppendA
*/
#include <string.h>
#include <winpr/wtypes.h>
#include <winpr/error.h>
#include <winpr/path.h>
#if defined(DEFINE_UNICODE) && (DEFINE_UNICODE != 0)
HRESULT PATH_CCH_APPEND(PWSTR pszPath, size_t cchPath, PCWSTR pszMore)
{
if (!pszPath)
return E_INVALIDARG;
if (!pszMore)
return E_INVALIDARG;
if ((cchPath == 0) || (cchPath > PATHCCH_MAX_CCH))
return E_INVALIDARG;
const size_t pszMoreLength = _wcsnlen(pszMore, cchPath);
const size_t pszPathLength = _wcsnlen(pszPath, cchPath);
BOOL pathBackslash = FALSE;
if (pszPathLength > 0)
pathBackslash = (pszPath[pszPathLength - 1] == CUR_PATH_SEPARATOR_CHR) ? TRUE : FALSE;
const BOOL moreBackslash = (pszMore[0] == CUR_PATH_SEPARATOR_CHR) ? TRUE : FALSE;
if (pathBackslash && moreBackslash)
{
if (pszMoreLength < 1)
return E_INVALIDARG;
if ((pszPathLength + pszMoreLength - 1) < cchPath)
{
WCHAR* ptr = &pszPath[pszPathLength];
*ptr = '\0';
_wcsncat(ptr, &pszMore[1], pszMoreLength - 1);
return S_OK;
}
}
else if ((pathBackslash && !moreBackslash) || (!pathBackslash && moreBackslash))
{
if ((pszPathLength + pszMoreLength) < cchPath)
{
WCHAR* ptr = &pszPath[pszPathLength];
*ptr = '\0';
_wcsncat(ptr, pszMore, pszMoreLength);
return S_OK;
}
}
else if (!pathBackslash && !moreBackslash)
{
if ((pszPathLength + pszMoreLength + 1) < cchPath)
{
WCHAR* ptr = &pszPath[pszPathLength];
*ptr = '\0';
_wcsncat(ptr, CUR_PATH_SEPARATOR_STR,
_wcsnlen(CUR_PATH_SEPARATOR_STR, ARRAYSIZE(CUR_PATH_SEPARATOR_STR)));
_wcsncat(ptr, pszMore, pszMoreLength);
return S_OK;
}
}
return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
}
#else
HRESULT PATH_CCH_APPEND(PSTR pszPath, size_t cchPath, PCSTR pszMore)
{
BOOL pathBackslash = FALSE;
BOOL moreBackslash = FALSE;
if (!pszPath)
return E_INVALIDARG;
if (!pszMore)
return E_INVALIDARG;
if ((cchPath == 0) || (cchPath > PATHCCH_MAX_CCH))
return E_INVALIDARG;
const size_t pszPathLength = strnlen(pszPath, cchPath);
if (pszPathLength > 0)
pathBackslash = (pszPath[pszPathLength - 1] == CUR_PATH_SEPARATOR_CHR) ? TRUE : FALSE;
const size_t pszMoreLength = strnlen(pszMore, cchPath);
if (pszMoreLength > 0)
moreBackslash = (pszMore[0] == CUR_PATH_SEPARATOR_CHR) ? TRUE : FALSE;
if (pathBackslash && moreBackslash)
{
if ((pszPathLength + pszMoreLength - 1) < cchPath)
{
sprintf_s(&pszPath[pszPathLength], cchPath - pszPathLength, "%s", &pszMore[1]);
return S_OK;
}
}
else if ((pathBackslash && !moreBackslash) || (!pathBackslash && moreBackslash))
{
if ((pszPathLength + pszMoreLength) < cchPath)
{
sprintf_s(&pszPath[pszPathLength], cchPath - pszPathLength, "%s", pszMore);
return S_OK;
}
}
else if (!pathBackslash && !moreBackslash)
{
if ((pszPathLength + pszMoreLength + 1) < cchPath)
{
sprintf_s(&pszPath[pszPathLength], cchPath - pszPathLength, "%s%s",
CUR_PATH_SEPARATOR_STR, pszMore);
return S_OK;
}
}
return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
}
#endif
/*
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef CUR_PATH_SEPARATOR_STR
#undef PATH_CCH_APPEND
*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,905 @@
/**
* WinPR: Windows Portable Runtime
* Path Functions
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* 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.
*/
#include <winpr/config.h>
#include <winpr/build-config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <winpr/crt.h>
#include <winpr/platform.h>
#include <winpr/file.h>
#include <winpr/tchar.h>
#include <winpr/environment.h>
#include <winpr/path.h>
#include <winpr/wlog.h>
#include "../file/file.h"
#include "../log.h"
#define TAG WINPR_TAG("path.shell")
#if defined(__IOS__)
#include "shell_ios.h"
#endif
#if defined(WIN32)
#include <windows.h>
#include <shlobj.h>
#else
#include <errno.h>
#include <dirent.h>
#endif
static char* GetPath_XDG_CONFIG_HOME(void);
static char* GetPath_XDG_RUNTIME_DIR(void);
/**
* SHGetKnownFolderPath function:
* http://msdn.microsoft.com/en-us/library/windows/desktop/bb762188/
*/
#if defined(WIN32) && !defined(_UWP)
static char* win_get_known_folder(REFKNOWNFOLDERID id, BOOL currentUser)
{
WCHAR* wpath = nullptr;
HANDLE handle = currentUser ? nullptr : (HANDLE)-1;
if (FAILED(SHGetKnownFolderPath(id, 0, handle, &wpath)))
return nullptr;
if (!wpath)
return nullptr;
char* path = ConvertWCharToUtf8Alloc(wpath, nullptr);
CoTaskMemFree(wpath);
return path;
}
#endif
/**
* XDG Base Directory Specification:
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
*/
char* GetEnvAlloc(LPCSTR lpName)
{
DWORD nSize = 0;
DWORD nStatus = 0;
char* env = nullptr;
nSize = GetEnvironmentVariableX(lpName, nullptr, 0);
if (nSize > 0)
{
env = malloc(nSize);
if (!env)
return nullptr;
nStatus = GetEnvironmentVariableX(lpName, env, nSize);
if (nStatus != (nSize - 1))
{
free(env);
return nullptr;
}
}
return env;
}
static char* GetPath_HOME(void)
{
char* path = nullptr;
#ifdef _WIN32
path = GetEnvAlloc("UserProfile");
#elif defined(__IOS__)
path = ios_get_home();
#else
path = GetEnvAlloc("HOME");
#endif
return path;
}
static char* GetPath_TEMP(void)
{
char* path = nullptr;
#ifdef _WIN32
path = GetEnvAlloc("TEMP");
#elif defined(__IOS__)
path = ios_get_temp();
#else
path = GetEnvAlloc("TMPDIR");
if (!path)
path = _strdup("/tmp");
#endif
return path;
}
static char* GetPath_XDG_DATA_HOME(void)
{
char* path = nullptr;
#if defined(WIN32) || defined(__IOS__)
path = GetPath_XDG_CONFIG_HOME();
#else
size_t size = 0;
char* home = nullptr;
/**
* There is a single base directory relative to which user-specific data files should be
* written. This directory is defined by the environment variable $XDG_DATA_HOME.
*
* $XDG_DATA_HOME defines the base directory relative to which user specific data files should
* be stored. If $XDG_DATA_HOME is either not set or empty, a default equal to
* $HOME/.local/share should be used.
*/
path = GetEnvAlloc("XDG_DATA_HOME");
if (path)
return path;
home = GetPath_HOME();
if (!home)
return nullptr;
size = strlen(home) + strlen("/.local/share") + 1;
path = (char*)malloc(size);
if (!path)
{
free(home);
return nullptr;
}
(void)sprintf_s(path, size, "%s%s", home, "/.local/share");
free(home);
#endif
return path;
}
static char* GetPath_XDG_CONFIG_HOME(void)
{
char* path = nullptr;
#if defined(WIN32) && !defined(_UWP)
path = win_get_known_folder(&FOLDERID_RoamingAppData, TRUE);
#elif defined(__IOS__)
path = ios_get_data();
#else
size_t size = 0;
char* home = nullptr;
/**
* There is a single base directory relative to which user-specific configuration files should
* be written. This directory is defined by the environment variable $XDG_CONFIG_HOME.
*
* $XDG_CONFIG_HOME defines the base directory relative to which user specific configuration
* files should be stored. If $XDG_CONFIG_HOME is either not set or empty, a default equal to
* $HOME/.config should be used.
*/
path = GetEnvAlloc("XDG_CONFIG_HOME");
if (path)
return path;
home = GetPath_HOME();
if (!home)
home = GetPath_TEMP();
if (!home)
return nullptr;
size = strlen(home) + strlen("/.config") + 1;
path = (char*)malloc(size);
if (!path)
{
free(home);
return nullptr;
}
(void)sprintf_s(path, size, "%s%s", home, "/.config");
free(home);
#endif
return path;
}
static char* GetPath_SYSTEM_CONFIG_HOME(void)
{
char* path = nullptr;
#if defined(WIN32) && !defined(_UWP)
path = win_get_known_folder(&FOLDERID_ProgramData, FALSE);
#elif defined(__IOS__)
path = ios_get_data();
#else
path = _strdup(WINPR_INSTALL_SYSCONFDIR);
#endif
return path;
}
static char* GetPath_XDG_CACHE_HOME(void)
{
char* path = nullptr;
#if defined(WIN32)
{
char* home = GetPath_XDG_RUNTIME_DIR();
if (home)
{
path = GetCombinedPath(home, "cache");
if (!winpr_PathFileExists(path))
if (!winpr_PathMakePath(path, nullptr))
path = nullptr;
}
free(home);
}
#elif defined(__IOS__)
path = ios_get_cache();
#else
size_t size = 0;
/**
* There is a single base directory relative to which user-specific non-essential (cached) data
* should be written. This directory is defined by the environment variable $XDG_CACHE_HOME.
*
* $XDG_CACHE_HOME defines the base directory relative to which user specific non-essential data
* files should be stored. If $XDG_CACHE_HOME is either not set or empty, a default equal to
* $HOME/.cache should be used.
*/
path = GetEnvAlloc("XDG_CACHE_HOME");
if (path)
return path;
char* home = GetPath_HOME();
if (!home)
return nullptr;
size = strlen(home) + strlen("/.cache") + 1;
path = (char*)malloc(size);
if (!path)
{
free(home);
return nullptr;
}
(void)sprintf_s(path, size, "%s%s", home, "/.cache");
free(home);
#endif
return path;
}
char* GetPath_XDG_RUNTIME_DIR(void)
{
char* path = nullptr;
#if defined(WIN32) && !defined(_UWP)
path = win_get_known_folder(&FOLDERID_LocalAppData, TRUE);
#else
/**
* There is a single base directory relative to which user-specific runtime files and other file
* objects should be placed. This directory is defined by the environment variable
* $XDG_RUNTIME_DIR.
*
* $XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential
* runtime files and other file objects (such as sockets, named pipes, ...) should be stored.
* The directory MUST be owned by the user, and he MUST be the only one having read and write
* access to it. Its Unix access mode MUST be 0700.
*
* The lifetime of the directory MUST be bound to the user being logged in. It MUST be created
* when the user first logs in and if the user fully logs out the directory MUST be removed. If
* the user logs in more than once he should get pointed to the same directory, and it is
* mandatory that the directory continues to exist from his first login to his last logout on
* the system, and not removed in between. Files in the directory MUST not survive reboot or a
* full logout/login cycle.
*
* The directory MUST be on a local file system and not shared with any other system. The
* directory MUST by fully-featured by the standards of the operating system. More specifically,
* on Unix-like operating systems AF_UNIX sockets, symbolic links, hard links, proper
* permissions, file locking, sparse files, memory mapping, file change notifications, a
* reliable hard link count must be supported, and no restrictions on the file name character
* set should be imposed. Files in this directory MAY be subjected to periodic clean-up. To
* ensure that your files are not removed, they should have their access time timestamp modified
* at least once every 6 hours of monotonic time or the 'sticky' bit should be set on the file.
*
* If $XDG_RUNTIME_DIR is not set applications should fall back to a replacement directory with
* similar capabilities and print a warning message. Applications should use this directory for
* communication and synchronization purposes and should not place larger files in it, since it
* might reside in runtime memory and cannot necessarily be swapped out to disk.
*/
path = GetEnvAlloc("XDG_RUNTIME_DIR");
#endif
if (path)
return path;
path = GetPath_TEMP();
return path;
}
char* GetKnownPath(eKnownPathTypes id)
{
char* path = nullptr;
switch (id)
{
case KNOWN_PATH_HOME:
path = GetPath_HOME();
break;
case KNOWN_PATH_TEMP:
path = GetPath_TEMP();
break;
case KNOWN_PATH_XDG_DATA_HOME:
path = GetPath_XDG_DATA_HOME();
break;
case KNOWN_PATH_XDG_CONFIG_HOME:
path = GetPath_XDG_CONFIG_HOME();
break;
case KNOWN_PATH_XDG_CACHE_HOME:
path = GetPath_XDG_CACHE_HOME();
break;
case KNOWN_PATH_XDG_RUNTIME_DIR:
path = GetPath_XDG_RUNTIME_DIR();
break;
case KNOWN_PATH_SYSTEM_CONFIG_HOME:
path = GetPath_SYSTEM_CONFIG_HOME();
break;
default:
path = nullptr;
break;
}
if (!path)
WLog_WARN(TAG, "Path %s is nullptr",
GetKnownPathIdString(WINPR_ASSERTING_INT_CAST(int, id)));
return path;
}
char* GetKnownSubPath(eKnownPathTypes id, const char* path)
{
if (!path)
return GetKnownSubPathV(id, "%s", "");
return GetKnownSubPathV(id, "%s", path);
}
char* GetKnownSubPathV(eKnownPathTypes id, const char* path, ...)
{
va_list ap = WINPR_C_ARRAY_INIT;
va_start(ap, path);
char* str = GetKnownSubPathVA(id, path, ap);
va_end(ap);
return str;
}
char* GetKnownSubPathVA(eKnownPathTypes id, const char* path, va_list ap)
{
char* knownPath = GetKnownPath(id);
if (!knownPath)
return nullptr;
char* subPath = GetCombinedPathVA(knownPath, path, ap);
free(knownPath);
return subPath;
}
char* GetEnvironmentPath(char* name)
{
char* env = nullptr;
DWORD nSize = 0;
DWORD nStatus = 0;
nSize = GetEnvironmentVariableX(name, nullptr, 0);
if (nSize)
{
env = (LPSTR)malloc(nSize);
if (!env)
return nullptr;
nStatus = GetEnvironmentVariableX(name, env, nSize);
if (nStatus != (nSize - 1))
{
free(env);
return nullptr;
}
}
return env;
}
char* GetEnvironmentSubPath(char* name, const char* path)
{
if (!path)
return GetEnvironmentSubPathV(name, "%s", "");
return GetEnvironmentSubPathV(name, "%s", path);
}
char* GetEnvironmentSubPathV(char* name, const char* path, ...)
{
va_list ap = WINPR_C_ARRAY_INIT;
va_start(ap, path);
char* str = GetEnvironmentSubPathVA(name, path, ap);
va_end(ap);
return str;
}
char* GetEnvironmentSubPathVA(char* name, WINPR_FORMAT_ARG const char* path, va_list ap)
{
char* env = GetEnvironmentPath(name);
if (!env)
return nullptr;
char* subpath = GetCombinedPathVA(env, path, ap);
free(env);
return subpath;
}
char* GetCombinedPath(const char* basePath, const char* subPathFmt)
{
if (!subPathFmt)
return GetCombinedPathV(basePath, "%s", "");
return GetCombinedPathV(basePath, "%s", subPathFmt);
}
char* GetCombinedPathV(const char* basePath, const char* subPathFmt, ...)
{
va_list ap = WINPR_C_ARRAY_INIT;
va_start(ap, subPathFmt);
char* str = GetCombinedPathVA(basePath, subPathFmt, ap);
va_end(ap);
return str;
}
char* GetCombinedPathVA(const char* basePath, WINPR_FORMAT_ARG const char* subPathFmt, va_list ap)
{
HRESULT status = 0;
char* subPathCpy = nullptr;
size_t basePathLength = 0;
size_t subPathLength = 0;
if (basePath)
basePathLength = strlen(basePath);
bool haveSubPath = subPathFmt && (*subPathFmt != '\0');
if (haveSubPath)
{
const int rc = winpr_vasprintf(&subPathCpy, &subPathLength, subPathFmt, ap);
if (rc < 0)
return nullptr;
if (rc == 0)
{
free(subPathCpy);
subPathCpy = nullptr;
subPathLength = 0;
haveSubPath = false;
}
}
const size_t length = basePathLength + subPathLength + 1;
char* path = (char*)calloc(1, length + 1);
if (!path)
goto fail;
if (basePath)
CopyMemory(path, basePath, basePathLength);
if (FAILED(PathCchConvertStyleA(path, basePathLength, PATH_STYLE_NATIVE)))
goto fail;
if (!haveSubPath)
return path;
if (!subPathCpy)
goto fail;
if (FAILED(PathCchConvertStyleA(subPathCpy, subPathLength, PATH_STYLE_NATIVE)))
goto fail;
status = NativePathCchAppendA(path, length + 1, subPathCpy);
if (FAILED(status))
goto fail;
free(subPathCpy);
return path;
fail:
free(path);
free(subPathCpy);
return nullptr;
}
BOOL PathMakePathA(LPCSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
{
#if defined(_UWP)
return FALSE;
#elif defined(_WIN32)
return (SHCreateDirectoryExA(nullptr, path, lpAttributes) == ERROR_SUCCESS);
#else
const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
char* dup = nullptr;
BOOL result = TRUE;
/* we only operate on a non-null, absolute path */
#if defined(__OS2__)
if (!path)
return FALSE;
#else
if (!path || *path != delim)
return FALSE;
#endif
if (!(dup = _strdup(path)))
return FALSE;
#ifdef __OS2__
p = (strlen(dup) > 3) && (dup[1] == ':') && (dup[2] == delim)) ? &dup[3] : dup;
while (p)
#else
for (char* p = dup; p;)
#endif
{
if ((p = strchr(p + 1, delim)))
*p = '\0';
if (mkdir(dup, 0777) != 0)
if (errno != EEXIST)
{
result = FALSE;
break;
}
if (p)
*p = delim;
}
free(dup);
return (result);
#endif
}
BOOL PathMakePathW(LPCWSTR path, WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpAttributes)
{
#if defined(_UWP)
return FALSE;
#elif defined(_WIN32)
return (SHCreateDirectoryExW(nullptr, path, lpAttributes) == ERROR_SUCCESS);
#else
const WCHAR wdelim = PathGetSeparatorW(PATH_STYLE_NATIVE);
const char delim = PathGetSeparatorA(PATH_STYLE_NATIVE);
char* dup = nullptr;
BOOL result = TRUE;
/* we only operate on a non-null, absolute path */
#if defined(__OS2__)
if (!path)
return FALSE;
#else
if (!path || *path != wdelim)
return FALSE;
#endif
dup = ConvertWCharToUtf8Alloc(path, nullptr);
if (!dup)
return FALSE;
#ifdef __OS2__
p = (strlen(dup) > 3) && (dup[1] == ':') && (dup[2] == delim)) ? &dup[3] : dup;
while (p)
#else
for (char* p = dup; p;)
#endif
{
if ((p = strchr(p + 1, delim)))
*p = '\0';
if (mkdir(dup, 0777) != 0)
if (errno != EEXIST)
{
result = FALSE;
break;
}
if (p)
*p = delim;
}
free(dup);
return (result);
#endif
}
#if !defined(_WIN32) || defined(_UWP)
BOOL PathIsRelativeA(LPCSTR pszPath)
{
if (!pszPath)
return FALSE;
return pszPath[0] != '/';
}
BOOL PathIsRelativeW(LPCWSTR pszPath)
{
LPSTR lpFileNameA = nullptr;
BOOL ret = FALSE;
if (!pszPath)
goto fail;
lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, nullptr);
if (!lpFileNameA)
goto fail;
ret = PathIsRelativeA(lpFileNameA);
fail:
free(lpFileNameA);
return ret;
}
BOOL PathFileExistsA(LPCSTR pszPath)
{
struct stat stat_info;
return (stat(pszPath, &stat_info) == 0);
}
BOOL PathFileExistsW(LPCWSTR pszPath)
{
LPSTR lpFileNameA = nullptr;
BOOL ret = FALSE;
if (!pszPath)
goto fail;
lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, nullptr);
if (!lpFileNameA)
goto fail;
ret = winpr_PathFileExists(lpFileNameA);
fail:
free(lpFileNameA);
return ret;
}
BOOL PathIsDirectoryEmptyA(LPCSTR pszPath)
{
struct dirent* dp = nullptr;
int empty = 1;
DIR* dir = opendir(pszPath);
if (dir == nullptr) /* Not a directory or doesn't exist */
return 1;
// NOLINTNEXTLINE(concurrency-mt-unsafe)
while ((dp = readdir(dir)) != nullptr)
{
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
continue; /* Skip . and .. */
empty = 0;
break;
}
closedir(dir);
return empty;
}
BOOL PathIsDirectoryEmptyW(LPCWSTR pszPath)
{
LPSTR lpFileNameA = nullptr;
BOOL ret = FALSE;
if (!pszPath)
goto fail;
lpFileNameA = ConvertWCharToUtf8Alloc(pszPath, nullptr);
if (!lpFileNameA)
goto fail;
ret = PathIsDirectoryEmptyA(lpFileNameA);
fail:
free(lpFileNameA);
return ret;
}
#endif
BOOL winpr_MoveFile(LPCSTR lpExistingFileName, LPCSTR lpNewFileName)
{
return winpr_MoveFileEx(lpExistingFileName, lpNewFileName, 0);
}
BOOL winpr_MoveFileEx(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD dwFlags)
{
#ifndef _WIN32
struct stat st;
int ret = 0;
ret = stat(lpNewFileName, &st);
if ((dwFlags & MOVEFILE_REPLACE_EXISTING) == 0)
{
if (ret == 0)
{
SetLastError(ERROR_ALREADY_EXISTS);
return FALSE;
}
}
else
{
if (ret == 0 && (st.st_mode & S_IWUSR) == 0)
{
SetLastError(ERROR_ACCESS_DENIED);
return FALSE;
}
}
ret = rename(lpExistingFileName, lpNewFileName);
if (ret != 0)
SetLastError(map_posix_err(errno));
return ret == 0;
#else
BOOL result = FALSE;
LPWSTR lpExistingFileNameW = nullptr;
LPWSTR lpNewFileNameW = nullptr;
if (!lpExistingFileName || !lpNewFileName)
return FALSE;
lpExistingFileNameW = ConvertUtf8ToWCharAlloc(lpExistingFileName, nullptr);
if (!lpExistingFileNameW)
goto cleanup;
lpNewFileNameW = ConvertUtf8ToWCharAlloc(lpNewFileName, nullptr);
if (!lpNewFileNameW)
goto cleanup;
result = MoveFileExW(lpExistingFileNameW, lpNewFileNameW, dwFlags);
cleanup:
free(lpExistingFileNameW);
free(lpNewFileNameW);
return result;
#endif
}
BOOL winpr_DeleteFile(const char* lpFileName)
{
#ifndef _WIN32
if (!lpFileName)
return FALSE;
const int status = unlink(lpFileName);
return (status != -1);
#else
LPWSTR lpFileNameW = nullptr;
BOOL result = FALSE;
if (lpFileName)
lpFileNameW = ConvertUtf8ToWCharAlloc(lpFileName, nullptr);
if (!lpFileNameW)
goto cleanup;
result = DeleteFileW(lpFileNameW);
cleanup:
free(lpFileNameW);
return result;
#endif
}
BOOL winpr_RemoveDirectory(LPCSTR lpPathName)
{
#ifndef _WIN32
int ret = rmdir(lpPathName);
if (ret != 0)
SetLastError(map_posix_err(errno));
else
SetLastError(STATUS_SUCCESS);
return ret == 0;
#else
LPWSTR lpPathNameW = nullptr;
BOOL result = FALSE;
if (lpPathName)
lpPathNameW = ConvertUtf8ToWCharAlloc(lpPathName, nullptr);
if (!lpPathNameW)
goto cleanup;
result = RemoveDirectoryW(lpPathNameW);
cleanup:
free(lpPathNameW);
return result;
#endif
}
BOOL winpr_PathFileExists(const char* pszPath)
{
if (!pszPath)
return FALSE;
#ifndef _WIN32
return PathFileExistsA(pszPath);
#else
WCHAR* pathW = ConvertUtf8ToWCharAlloc(pszPath, nullptr);
BOOL result = FALSE;
if (!pathW)
return FALSE;
result = PathFileExistsW(pathW);
free(pathW);
return result;
#endif
}
BOOL winpr_PathMakePath(const char* path, LPSECURITY_ATTRIBUTES lpAttributes)
{
if (!path)
return FALSE;
#ifndef _WIN32
return PathMakePathA(path, lpAttributes);
#else
WCHAR* pathW = ConvertUtf8ToWCharAlloc(path, nullptr);
BOOL result = FALSE;
if (!pathW)
return FALSE;
result = SHCreateDirectoryExW(nullptr, pathW, lpAttributes) == ERROR_SUCCESS;
free(pathW);
return result;
#endif
}

View File

@@ -0,0 +1,9 @@
#ifndef SHELL_IOS_H_
#define SHELL_IOS_H_
char* ios_get_home(void);
char* ios_get_temp(void);
char* ios_get_data(void);
char* ios_get_cache(void);
#endif

View File

@@ -0,0 +1,54 @@
/**
* WinPR: Windows Portable Runtime
* Path Functions
*
* Copyright 2016 Armin Novak <armin.novak@thincast.om>
* Copyright 2016 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.
*/
#import <Foundation/Foundation.h>
#include <winpr/config.h>
#include "shell_ios.h"
static NSString *ios_get_directory_for_search_path(NSSearchPathDirectory searchPath)
{
return [NSSearchPathForDirectoriesInDomains(searchPath, NSUserDomainMask, YES) lastObject];
}
char *ios_get_home(void)
{
NSString *path = ios_get_directory_for_search_path(NSDocumentDirectory);
return strdup([path UTF8String]);
}
char *ios_get_temp(void)
{
NSString *tmp_path = NSTemporaryDirectory();
return strdup([tmp_path UTF8String]);
}
char *ios_get_data(void)
{
NSString *path = ios_get_directory_for_search_path(NSApplicationSupportDirectory);
return strdup([path UTF8String]);
}
char *ios_get_cache(void)
{
NSString *path = ios_get_directory_for_search_path(NSCachesDirectory);
return strdup([path UTF8String]);
}

View File

@@ -0,0 +1,48 @@
set(MODULE_NAME "TestPath")
set(MODULE_PREFIX "TEST_PATH")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS
TestPathCchAddBackslash.c
TestPathCchRemoveBackslash.c
TestPathCchAddBackslashEx.c
TestPathCchRemoveBackslashEx.c
TestPathCchAddExtension.c
TestPathCchAppend.c
TestPathCchAppendEx.c
TestPathCchCanonicalize.c
TestPathCchCanonicalizeEx.c
TestPathAllocCanonicalize.c
TestPathCchCombine.c
TestPathCchCombineEx.c
TestPathAllocCombine.c
TestPathCchFindExtension.c
TestPathCchRenameExtension.c
TestPathCchRemoveExtension.c
TestPathCchIsRoot.c
TestPathIsUNCEx.c
TestPathCchSkipRoot.c
TestPathCchStripToRoot.c
TestPathCchStripPrefix.c
TestPathCchRemoveFileSpec.c
TestPathShell.c
TestPathMakePath.c
)
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
target_link_libraries(${MODULE_NAME} winpr)
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathAllocCanonicalize(int argc, char* argv[])
{
printf("Warning: %s is not implemented!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,98 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
static const TCHAR testBasePathBackslash[] = _T("C:\\Program Files\\");
static const TCHAR testBasePathNoBackslash[] = _T("C:\\Program Files");
static const TCHAR testMorePathBackslash[] = _T("\\Microsoft Visual Studio 11.0");
static const TCHAR testMorePathNoBackslash[] = _T("Microsoft Visual Studio 11.0");
static const TCHAR testPathOut[] = _T("C:\\Program Files\\Microsoft Visual Studio 11.0");
static const TCHAR testPathOutMorePathBackslash[] = _T("C:\\Microsoft Visual Studio 11.0");
int TestPathAllocCombine(int argc, char* argv[])
{
HRESULT status = 0;
LPTSTR PathOut = nullptr;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/* Base Path: Backslash, More Path: No Backslash */
status = PathAllocCombine(testBasePathBackslash, testMorePathNoBackslash, 0, &PathOut);
if (status != S_OK)
{
_tprintf(_T("PathAllocCombine status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcscmp(PathOut, testPathOut) != 0)
{
_tprintf(_T("Path Mismatch 1: Actual: %s, Expected: %s\n"), PathOut, testPathOut);
return -1;
}
free(PathOut);
/* Base Path: Backslash, More Path: Backslash */
status = PathAllocCombine(testBasePathBackslash, testMorePathBackslash, 0, &PathOut);
if (status != S_OK)
{
_tprintf(_T("PathAllocCombine status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcscmp(PathOut, testPathOutMorePathBackslash) != 0)
{
_tprintf(_T("Path Mismatch 2: Actual: %s, Expected: %s\n"), PathOut,
testPathOutMorePathBackslash);
return -1;
}
free(PathOut);
/* Base Path: No Backslash, More Path: Backslash */
status = PathAllocCombine(testBasePathNoBackslash, testMorePathBackslash, 0, &PathOut);
if (status != S_OK)
{
_tprintf(_T("PathAllocCombine status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcscmp(PathOut, testPathOutMorePathBackslash) != 0)
{
_tprintf(_T("Path Mismatch 3: Actual: %s, Expected: %s\n"), PathOut,
testPathOutMorePathBackslash);
return -1;
}
free(PathOut);
/* Base Path: No Backslash, More Path: No Backslash */
status = PathAllocCombine(testBasePathNoBackslash, testMorePathNoBackslash, 0, &PathOut);
if (status != S_OK)
{
_tprintf(_T("PathAllocCombine status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcscmp(PathOut, testPathOut) != 0)
{
_tprintf(_T("Path Mismatch 4: Actual: %s, Expected: %s\n"), PathOut, testPathOut);
return -1;
}
free(PathOut);
return 0;
}

View File

@@ -0,0 +1,101 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
static const TCHAR testPathBackslash[] = _T("C:\\Program Files\\");
static const TCHAR testPathNoBackslash[] = _T("C:\\Program Files");
int TestPathCchAddBackslash(int argc, char* argv[])
{
HRESULT status = 0;
TCHAR Path[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/**
* PathCchAddBackslash returns S_OK if the function was successful,
* S_FALSE if the path string already ends in a backslash,
* or an error code otherwise.
*/
_tcsncpy(Path, testPathNoBackslash, ARRAYSIZE(Path));
/* Add a backslash to a path without a trailing backslash, expect S_OK */
status = PathCchAddBackslash(Path, PATHCCH_MAX_CCH);
if (status != S_OK)
{
_tprintf(_T("PathCchAddBackslash status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcsncmp(Path, testPathBackslash, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path, testPathBackslash);
return -1;
}
/* Add a backslash to a path with a trailing backslash, expect S_FALSE */
_tcsncpy(Path, testPathBackslash, ARRAYSIZE(Path));
status = PathCchAddBackslash(Path, PATHCCH_MAX_CCH);
if (status != S_FALSE)
{
_tprintf(_T("PathCchAddBackslash status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcsncmp(Path, testPathBackslash, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path, testPathBackslash);
return -1;
}
/* Use nullptr PSTR, expect FAILED(status) */
status = PathCchAddBackslash(nullptr, PATHCCH_MAX_CCH);
if (SUCCEEDED(status))
{
_tprintf(
_T("PathCchAddBackslash unexpectedly succeeded with null buffer. Status: 0x%08") _T(
PRIX32) _T("\n"),
status);
return -1;
}
/* Use insufficient size value, expect FAILED(status) */
_tcsncpy(Path, _T("C:\\tmp"), ARRAYSIZE(Path));
status = PathCchAddBackslash(Path, 7);
if (SUCCEEDED(status))
{
_tprintf(_T("PathCchAddBackslash unexpectedly succeeded with insufficient buffer size. ")
_T("Status: 0x%08") _T(PRIX32) _T("\n"),
status);
return -1;
}
/* Use minimum required size value, expect S_OK */
_tcsncpy(Path, _T("C:\\tmp"), ARRAYSIZE(Path));
status = PathCchAddBackslash(Path, 8);
if (status != S_OK)
{
_tprintf(_T("PathCchAddBackslash failed with status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
return 0;
}

View File

@@ -0,0 +1,103 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
static const TCHAR testPathBackslash[] = _T("C:\\Program Files\\");
static const TCHAR testPathNoBackslash[] = _T("C:\\Program Files");
int TestPathCchAddBackslashEx(int argc, char* argv[])
{
HRESULT status = 0;
LPTSTR pszEnd = nullptr;
size_t cchRemaining = 0;
TCHAR Path[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/**
* PathCchAddBackslashEx returns S_OK if the function was successful,
* S_FALSE if the path string already ends in a backslash,
* or an error code otherwise.
*/
_tcsncpy(Path, testPathNoBackslash, ARRAYSIZE(Path));
/* Add a backslash to a path without a trailing backslash, expect S_OK */
status = PathCchAddBackslashEx(Path, sizeof(Path) / sizeof(TCHAR), &pszEnd, &cchRemaining);
if (status != S_OK)
{
_tprintf(_T("PathCchAddBackslash status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcsncmp(Path, testPathBackslash, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path, testPathBackslash);
return -1;
}
/* Add a backslash to a path with a trailing backslash, expect S_FALSE */
_tcsncpy(Path, testPathBackslash, ARRAYSIZE(Path));
status = PathCchAddBackslashEx(Path, sizeof(Path) / sizeof(TCHAR), &pszEnd, &cchRemaining);
if (status != S_FALSE)
{
_tprintf(_T("PathCchAddBackslash status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcsncmp(Path, testPathBackslash, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path, testPathBackslash);
return -1;
}
/* Use nullptr PSTR, expect FAILED(status) */
status = PathCchAddBackslashEx(nullptr, PATHCCH_MAX_CCH, nullptr, nullptr);
if (SUCCEEDED(status))
{
_tprintf(
_T("PathCchAddBackslashEx unexpectedly succeeded with null buffer. Status: 0x%08") _T(
PRIX32) _T("\n"),
status);
return -1;
}
/* Use insufficient size value, expect FAILED(status) */
_tcsncpy(Path, _T("C:\\tmp"), ARRAYSIZE(Path));
status = PathCchAddBackslashEx(Path, 7, nullptr, nullptr);
if (SUCCEEDED(status))
{
_tprintf(_T("PathCchAddBackslashEx unexpectedly succeeded with insufficient buffer size. ")
_T("Status: 0x%08") _T(PRIX32) _T("\n"),
status);
return -1;
}
/* Use minimum required size value, expect S_OK */
_tcsncpy(Path, _T("C:\\tmp"), ARRAYSIZE(Path));
status = PathCchAddBackslashEx(Path, 8, nullptr, nullptr);
if (status != S_OK)
{
_tprintf(_T("PathCchAddBackslashEx failed with status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
return 0;
}

View File

@@ -0,0 +1,140 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
static const TCHAR testExtDot[] = _T(".exe");
static const TCHAR testExtNoDot[] = _T("exe");
static const TCHAR testPathNoExtension[] = _T("C:\\Windows\\System32\\cmd");
static const TCHAR testPathExtension[] = _T("C:\\Windows\\System32\\cmd.exe");
int TestPathCchAddExtension(int argc, char* argv[])
{
HRESULT status = 0;
TCHAR Path[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/* Path: no extension, Extension: dot */
_tcsncpy(Path, testPathNoExtension, ARRAYSIZE(Path));
status = PathCchAddExtension(Path, PATHCCH_MAX_CCH, testExtDot);
if (status != S_OK)
{
_tprintf(_T("PathCchAddExtension status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcsncmp(Path, testPathExtension, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path, testPathExtension);
return -1;
}
/* Path: no extension, Extension: no dot */
_tcsncpy(Path, testPathNoExtension, ARRAYSIZE(Path));
status = PathCchAddExtension(Path, PATHCCH_MAX_CCH, testExtNoDot);
if (status != S_OK)
{
_tprintf(_T("PathCchAddExtension status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcsncmp(Path, testPathExtension, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path, testPathExtension);
return -1;
}
/* Path: extension, Extension: dot */
_tcsncpy(Path, testPathExtension, ARRAYSIZE(Path));
status = PathCchAddExtension(Path, PATHCCH_MAX_CCH, testExtDot);
if (status != S_FALSE)
{
_tprintf(_T("PathCchAddExtension status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcsncmp(Path, testPathExtension, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path, testPathExtension);
return -1;
}
/* Path: extension, Extension: no dot */
_tcsncpy(Path, testPathExtension, ARRAYSIZE(Path));
status = PathCchAddExtension(Path, PATHCCH_MAX_CCH, testExtDot);
if (status != S_FALSE)
{
_tprintf(_T("PathCchAddExtension status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcsncmp(Path, testPathExtension, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path, testPathExtension);
return -1;
}
/* Path: nullptr */
status = PathCchAddExtension(nullptr, PATHCCH_MAX_CCH, testExtDot);
if (status != E_INVALIDARG)
{
_tprintf(_T("PathCchAddExtension with null buffer returned status: 0x%08") _T(
PRIX32) _T(" (expected E_INVALIDARG)\n"),
status);
return -1;
}
/* Extension: nullptr */
status = PathCchAddExtension(Path, PATHCCH_MAX_CCH, nullptr);
if (status != E_INVALIDARG)
{
_tprintf(_T("PathCchAddExtension with null extension returned status: 0x%08") _T(
PRIX32) _T(" (expected E_INVALIDARG)\n"),
status);
return -1;
}
/* Insufficient Buffer size */
_tcsncpy(Path, _T("C:\\456789"), ARRAYSIZE(Path));
status = PathCchAddExtension(Path, 9 + 4, _T(".jpg"));
if (SUCCEEDED(status))
{
_tprintf(_T("PathCchAddExtension with insufficient buffer unexpectedly succeeded with ")
_T("status: 0x%08") _T(PRIX32) _T("\n"),
status);
return -1;
}
/* Minimum required buffer size */
_tcsncpy(Path, _T("C:\\456789"), ARRAYSIZE(Path));
status = PathCchAddExtension(Path, 9 + 4 + 1, _T(".jpg"));
if (FAILED(status))
{
_tprintf(_T("PathCchAddExtension with sufficient buffer unexpectedly failed with status: ")
_T("0x%08") _T(PRIX32) _T("\n"),
status);
return -1;
}
return 0;
}

View File

@@ -0,0 +1,151 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
static const TCHAR testBasePathBackslash[] = _T("C:\\Program Files\\");
static const TCHAR testBasePathNoBackslash[] = _T("C:\\Program Files");
static const TCHAR testMorePathBackslash[] = _T("\\Microsoft Visual Studio 11.0");
static const TCHAR testMorePathNoBackslash[] = _T("Microsoft Visual Studio 11.0");
static const TCHAR testPathOut[] = _T("C:\\Program Files\\Microsoft Visual Studio 11.0");
int TestPathCchAppend(int argc, char* argv[])
{
HRESULT status = 0;
TCHAR Path[PATHCCH_MAX_CCH];
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/* Base Path: Backslash, More Path: No Backslash */
_tcsncpy(Path, testBasePathBackslash, ARRAYSIZE(Path));
status = PathCchAppend(Path, PATHCCH_MAX_CCH, testMorePathNoBackslash);
if (status != S_OK)
{
_tprintf(_T("PathCchAppend status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcsncmp(Path, testPathOut, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path, testPathOut);
return -1;
}
/* Base Path: Backslash, More Path: Backslash */
_tcsncpy(Path, testBasePathBackslash, ARRAYSIZE(Path));
status = PathCchAppend(Path, PATHCCH_MAX_CCH, testMorePathBackslash);
if (status != S_OK)
{
_tprintf(_T("PathCchAppend status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcsncmp(Path, testPathOut, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path, testPathOut);
return -1;
}
/* Base Path: No Backslash, More Path: Backslash */
_tcsncpy(Path, testBasePathNoBackslash, ARRAYSIZE(Path));
status = PathCchAppend(Path, PATHCCH_MAX_CCH, testMorePathBackslash);
if (status != S_OK)
{
_tprintf(_T("PathCchAppend status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcsncmp(Path, testPathOut, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path, testPathOut);
return -1;
}
/* Base Path: No Backslash, More Path: No Backslash */
_tcsncpy(Path, testBasePathNoBackslash, ARRAYSIZE(Path));
status = PathCchAppend(Path, PATHCCH_MAX_CCH, testMorePathNoBackslash);
if (status != S_OK)
{
_tprintf(_T("PathCchAppend status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcsncmp(Path, testPathOut, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path, testPathOut);
return -1;
}
/* According to msdn a nullptr Path is an invalid argument */
status = PathCchAppend(nullptr, PATHCCH_MAX_CCH, testMorePathNoBackslash);
if (status != E_INVALIDARG)
{
_tprintf(_T("PathCchAppend with nullptr path unexpectedly returned status: 0x%08") _T(
PRIX32) _T("\n"),
status);
return -1;
}
/* According to msdn a nullptr pszMore is an invalid argument (although optional !?) */
_tcsncpy(Path, testBasePathNoBackslash, ARRAYSIZE(Path));
status = PathCchAppend(Path, PATHCCH_MAX_CCH, nullptr);
if (status != E_INVALIDARG)
{
_tprintf(_T("PathCchAppend with nullptr pszMore unexpectedly returned status: 0x%08") _T(
PRIX32) _T("\n"),
status);
return -1;
}
/* According to msdn cchPath must be > 0 and <= PATHCCH_MAX_CCH */
_tcsncpy(Path, testBasePathNoBackslash, ARRAYSIZE(Path));
status = PathCchAppend(Path, 0, testMorePathNoBackslash);
if (status != E_INVALIDARG)
{
_tprintf(_T("PathCchAppend with cchPath value 0 unexpectedly returned status: 0x%08") _T(
PRIX32) _T("\n"),
status);
return -1;
}
_tcsncpy(Path, testBasePathNoBackslash, ARRAYSIZE(Path));
status = PathCchAppend(Path, PATHCCH_MAX_CCH + 1, testMorePathNoBackslash);
if (status != E_INVALIDARG)
{
_tprintf(_T("PathCchAppend with cchPath value > PATHCCH_MAX_CCH unexpectedly returned ")
_T("status: 0x%08") _T(PRIX32) _T("\n"),
status);
return -1;
}
/* Resulting file must not exceed PATHCCH_MAX_CCH */
for (size_t i = 0; i < PATHCCH_MAX_CCH - 1; i++)
Path[i] = _T('X');
Path[PATHCCH_MAX_CCH - 1] = 0;
status = PathCchAppend(Path, PATHCCH_MAX_CCH, _T("\\This cannot be appended to Path"));
if (SUCCEEDED(status))
{
_tprintf(_T("PathCchAppend unexpectedly succeeded with status: 0x%08") _T(PRIX32) _T("\n"),
status);
return -1;
}
return 0;
}

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathCchAppendEx(int argc, char* argv[])
{
printf("Warning: %s is not implemented!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathCchCanonicalize(int argc, char* argv[])
{
printf("Warning: %s is not implemented!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathCchCanonicalizeEx(int argc, char* argv[])
{
printf("Warning: %s is not implemented!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathCchCombine(int argc, char* argv[])
{
printf("Warning: %s is not implemented!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathCchCombineEx(int argc, char* argv[])
{
printf("Warning: %s is not implemented!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,114 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
static const char testPathExtension[] = "C:\\Windows\\System32\\cmd.exe";
int TestPathCchFindExtension(int argc, char* argv[])
{
PCSTR pszExt = nullptr;
PCSTR pszTmp = nullptr;
HRESULT hr = 0;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/* Test invalid args */
hr = PathCchFindExtensionA(nullptr, sizeof(testPathExtension), &pszExt);
if (SUCCEEDED(hr))
{
printf("PathCchFindExtensionA unexpectedly succeeded with pszPath = nullptr. result: "
"0x%08" PRIX32 "\n",
hr);
return -1;
}
hr = PathCchFindExtensionA(testPathExtension, 0, &pszExt);
if (SUCCEEDED(hr))
{
printf("PathCchFindExtensionA unexpectedly succeeded with cchPath = 0. result: 0x%08" PRIX32
"\n",
hr);
return -1;
}
hr = PathCchFindExtensionA(testPathExtension, sizeof(testPathExtension), nullptr);
if (SUCCEEDED(hr))
{
printf("PathCchFindExtensionA unexpectedly succeeded with ppszExt = nullptr. result: "
"0x%08" PRIX32 "\n",
hr);
return -1;
}
/* Test missing null-termination of pszPath */
hr = PathCchFindExtensionA("c:\\45.789", 9, &pszExt); /* nb: correct would be 10 */
if (SUCCEEDED(hr))
{
printf("PathCchFindExtensionA unexpectedly succeeded with unterminated pszPath. result: "
"0x%08" PRIX32 "\n",
hr);
return -1;
}
/* Test passing of an empty terminated string (must succeed) */
pszExt = nullptr;
pszTmp = "";
hr = PathCchFindExtensionA(pszTmp, 1, &pszExt);
if (hr != S_OK)
{
printf("PathCchFindExtensionA failed with an empty terminated string. result: 0x%08" PRIX32
"\n",
hr);
return -1;
}
/* pszExt must point to the strings terminating 0 now */
if (pszExt != pszTmp)
{
printf("PathCchFindExtensionA failed with an empty terminated string: pszExt pointer "
"mismatch\n");
return -1;
}
/* Test a path without file extension (must succeed) */
pszExt = nullptr;
pszTmp = "c:\\4.678\\";
hr = PathCchFindExtensionA(pszTmp, 10, &pszExt);
if (hr != S_OK)
{
printf("PathCchFindExtensionA failed with a directory path. result: 0x%08" PRIX32 "\n", hr);
return -1;
}
/* The extension must not have been found and pszExt must point to the
* strings terminating nullptr now */
if (pszExt != &pszTmp[9])
{
printf("PathCchFindExtensionA failed with a directory path: pszExt pointer mismatch\n");
return -1;
}
/* Non-special tests */
pszExt = nullptr;
if (PathCchFindExtensionA(testPathExtension, sizeof(testPathExtension), &pszExt) != S_OK)
{
printf("PathCchFindExtensionA failure: expected S_OK\n");
return -1;
}
if (!pszExt || strcmp(pszExt, ".exe") != 0)
{
printf("PathCchFindExtensionA failure: unexpected extension\n");
return -1;
}
printf("Extension: %s\n", pszExt);
return 0;
}

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathCchIsRoot(int argc, char* argv[])
{
printf("Warning: %s is not implemented!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathCchRemoveBackslash(int argc, char* argv[])
{
printf("Warning: %s is not implemented!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathCchRemoveBackslashEx(int argc, char* argv[])
{
printf("Warning: %s is not implemented!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathCchRemoveExtension(int argc, char* argv[])
{
printf("Warning: %s is not implemented!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathCchRemoveFileSpec(int argc, char* argv[])
{
printf("Warning: %s is not implemented!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathCchRenameExtension(int argc, char* argv[])
{
printf("Warning: %s is not implemented!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathCchSkipRoot(int argc, char* argv[])
{
printf("Warning: %s is not implemented!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,128 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
/**
* Naming Files, Paths, and Namespaces:
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247/
*/
static const TCHAR testPathPrefixFileNamespace[] = _T("\\\\?\\C:\\Program Files\\");
static const TCHAR testPathNoPrefixFileNamespace[] = _T("C:\\Program Files\\");
static const TCHAR testPathPrefixFileNamespaceMinimum[] = _T("\\\\?\\C:");
static const TCHAR testPathNoPrefixFileNamespaceMinimum[] = _T("C:");
static const TCHAR testPathPrefixDeviceNamespace[] = _T("\\\\?\\GLOBALROOT");
int TestPathCchStripPrefix(int argc, char* argv[])
{
HRESULT status = 0;
TCHAR Path[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/**
* PathCchStripPrefix returns S_OK if the prefix was removed, S_FALSE if
* the path did not have a prefix to remove, or an HRESULT failure code.
*/
/* Path with prefix (File Namespace) */
_tcsncpy(Path, testPathPrefixFileNamespace, ARRAYSIZE(Path));
status = PathCchStripPrefix(Path, sizeof(testPathPrefixFileNamespace) / sizeof(TCHAR));
if (status != S_OK)
{
_tprintf(_T("PathCchStripPrefix status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcsncmp(Path, testPathNoPrefixFileNamespace, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path,
testPathNoPrefixFileNamespace);
return -1;
}
/* Path with prefix (Device Namespace) */
_tcsncpy(Path, testPathPrefixDeviceNamespace, ARRAYSIZE(Path));
status = PathCchStripPrefix(Path, ARRAYSIZE(testPathPrefixDeviceNamespace));
if (status != S_FALSE)
{
_tprintf(_T("PathCchStripPrefix status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
if (_tcsncmp(Path, testPathPrefixDeviceNamespace, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path,
testPathPrefixDeviceNamespace);
return -1;
}
/* nullptr Path */
status = PathCchStripPrefix(nullptr, PATHCCH_MAX_CCH);
if (status != E_INVALIDARG)
{
_tprintf(
_T("PathCchStripPrefix with null path unexpectedly succeeded with status 0x%08") _T(
PRIX32) _T("\n"),
status);
return -1;
}
/* Invalid cchPath values: 0, 1, 2, 3 and > PATHCCH_MAX_CCH */
for (int i = 0; i < 5; i++)
{
_tcsncpy(Path, testPathPrefixFileNamespace, ARRAYSIZE(Path));
if (i == 4)
i = PATHCCH_MAX_CCH + 1;
status = PathCchStripPrefix(Path, i);
if (status != E_INVALIDARG)
{
_tprintf(_T("PathCchStripPrefix with invalid cchPath value %d unexpectedly succeeded ")
_T("with status 0x%08") _T(PRIX32) _T("\n"),
i, status);
return -1;
}
}
/* Minimum Path that would get successfully stripped on windows */
_tcsncpy(Path, testPathPrefixFileNamespaceMinimum, ARRAYSIZE(Path));
size_t i = ARRAYSIZE(testPathPrefixFileNamespaceMinimum);
i = i - 1; /* include testing of a non-null terminated string */
status = PathCchStripPrefix(Path, i);
if (status != S_OK)
{
_tprintf(_T("PathCchStripPrefix with minimum valid strippable path length unexpectedly ")
_T("returned status 0x%08") _T(PRIX32) _T("\n"),
status);
return -1;
}
if (_tcsncmp(Path, testPathNoPrefixFileNamespaceMinimum, ARRAYSIZE(Path)) != 0)
{
_tprintf(_T("Path Mismatch: Actual: %s, Expected: %s\n"), Path,
testPathNoPrefixFileNamespaceMinimum);
return -1;
}
/* Invalid drive letter symbol */
_tcsncpy(Path, _T("\\\\?\\5:"), ARRAYSIZE(Path));
status = PathCchStripPrefix(Path, 6);
if (status == S_OK)
{
_tprintf(
_T("PathCchStripPrefix with invalid drive letter symbol unexpectedly succeeded\n"));
return -1;
}
return 0;
}

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathCchStripToRoot(int argc, char* argv[])
{
printf("Warning: %s is not implemented!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,52 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
static const TCHAR testServer[] = _T("server\\share\\path\\file");
static const TCHAR testPathUNC[] = _T("\\\\server\\share\\path\\file");
static const TCHAR testPathNotUNC[] = _T("C:\\share\\path\\file");
int TestPathIsUNCEx(int argc, char* argv[])
{
BOOL status = 0;
LPCTSTR Server = nullptr;
TCHAR Path[PATHCCH_MAX_CCH] = WINPR_C_ARRAY_INIT;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/* Path is UNC */
_tcsncpy(Path, testPathUNC, ARRAYSIZE(Path));
status = PathIsUNCEx(Path, &Server);
if (!status)
{
_tprintf(_T("PathIsUNCEx status: 0x%d\n"), status);
return -1;
}
if (_tcsncmp(Server, testServer, ARRAYSIZE(testServer)) != 0)
{
_tprintf(_T("Server Name Mismatch: Actual: %s, Expected: %s\n"), Server, testServer);
return -1;
}
/* Path is not UNC */
_tcsncpy(Path, testPathNotUNC, ARRAYSIZE(Path));
status = PathIsUNCEx(Path, &Server);
if (status)
{
_tprintf(_T("PathIsUNCEx status: 0x%08") _T(PRIX32) _T("\n"), status);
return -1;
}
return 0;
}

View File

@@ -0,0 +1,96 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <winpr/crt.h>
#include <winpr/crypto.h>
#include <winpr/file.h>
#include <winpr/path.h>
static UINT32 prand(UINT32 max)
{
UINT32 tmp = 0;
if (max <= 1)
return 1;
if (winpr_RAND(&tmp, sizeof(tmp)) < 0)
{
// NOLINTNEXTLINE(concurrency-mt-unsafe)
exit(-1);
}
return tmp % (max - 1) + 1;
}
int TestPathMakePath(int argc, char* argv[])
{
size_t baseLen = 0;
BOOL success = 0;
char tmp[64] = WINPR_C_ARRAY_INIT;
char* path = nullptr;
char* cur = nullptr;
char delim = PathGetSeparatorA(0);
char* base = GetKnownPath(KNOWN_PATH_TEMP);
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (!base)
{
(void)fprintf(stderr, "Failed to get temporary directory!\n");
return -1;
}
baseLen = strlen(base);
for (int x = 0; x < 5; x++)
{
(void)sprintf_s(tmp, ARRAYSIZE(tmp), "%08" PRIX32, prand(UINT32_MAX));
path = GetCombinedPath(base, tmp);
free(base);
if (!path)
{
(void)fprintf(stderr, "GetCombinedPath failed!\n");
return -1;
}
base = path;
}
printf("Creating path %s\n", path);
success = winpr_PathMakePath(path, nullptr);
if (!success)
{
(void)fprintf(stderr, "MakePath failed!\n");
free(path);
return -1;
}
success = winpr_PathFileExists(path);
if (!success)
{
(void)fprintf(stderr, "MakePath lied about success!\n");
free(path);
return -1;
}
while (strlen(path) > baseLen)
{
if (!winpr_RemoveDirectory(path))
{
(void)fprintf(stderr, "winpr_RemoveDirectory %s failed!\n", path);
free(path);
return -1;
}
cur = strrchr(path, delim);
if (cur)
*cur = '\0';
}
free(path);
printf("%s success!\n", __func__);
return 0;
}

View File

@@ -0,0 +1,58 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/tchar.h>
#include <winpr/winpr.h>
int TestPathShell(int argc, char* argv[])
{
const int paths[] = { KNOWN_PATH_HOME, KNOWN_PATH_TEMP,
KNOWN_PATH_XDG_DATA_HOME, KNOWN_PATH_XDG_CONFIG_HOME,
KNOWN_PATH_XDG_CACHE_HOME, KNOWN_PATH_XDG_RUNTIME_DIR,
KNOWN_PATH_XDG_CONFIG_HOME };
const char* names[] = { "KNOWN_PATH_HOME", "KNOWN_PATH_TEMP",
"KNOWN_PATH_XDG_DATA_HOME", "KNOWN_PATH_XDG_CONFIG_HOME",
"KNOWN_PATH_XDG_CACHE_HOME", "KNOWN_PATH_XDG_RUNTIME_DIR",
"KNOWN_PATH_XDG_CONFIG_HOME" };
int rc = 0;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
for (size_t x = 0; x < sizeof(paths) / sizeof(paths[0]); x++)
{
const int id = paths[x];
const char* name = names[x];
{
char* path = GetKnownPath(id);
if (!path)
{
(void)fprintf(stderr, "GetKnownPath(%d) failed\n", id);
rc = -1;
}
else
{
printf("%s Path: %s\n", name, path);
}
free(path);
}
{
char* path = GetKnownSubPath(id, "freerdp");
if (!path)
{
(void)fprintf(stderr, "GetKnownSubPath(%d) failed\n", id);
rc = -1;
}
else
{
printf("%s SubPath: %s\n", name, path);
}
free(path);
}
}
return rc;
}