Files
orbithub/third_party/FreeRDP/winpr/libwinpr/path/path.c

1259 lines
31 KiB
C

/**
* WinPR: Windows Portable Runtime
* Path 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/version.h>
#include <winpr/build-config.h>
#include <winpr/crt.h>
#include <winpr/tchar.h>
#include <winpr/path.h>
#include <winpr/file.h>
#include "../utils.h"
#if defined(WITH_RESOURCE_VERSIONING)
#define STR(x) #x
#endif
static const char PATH_SLASH_CHR = '/';
static const char PATH_SLASH_STR[] = "/";
static const char PATH_BACKSLASH_CHR = '\\';
static const char PATH_BACKSLASH_STR[] = "\\";
#ifdef _WIN32
static const WCHAR PATH_SLASH_CHR_W = L'/';
static const WCHAR PATH_BACKSLASH_CHR_W = L'\\';
static const WCHAR PATH_SLASH_STR_W[] = L"/";
static const WCHAR PATH_BACKSLASH_STR_W[] = L"\\";
#else
#if defined(__BIG_ENDIAN__)
static const WCHAR PATH_SLASH_CHR_W = 0x2f00;
static const WCHAR PATH_BACKSLASH_CHR_W = 0x5c00;
static const WCHAR PATH_SLASH_STR_W[] = { 0x2f00, '\0' };
static const WCHAR PATH_BACKSLASH_STR_W[] = { 0x5c00, '\0' };
#else
static const WCHAR PATH_SLASH_CHR_W = '/';
static const WCHAR PATH_BACKSLASH_CHR_W = '\\';
static const WCHAR PATH_SLASH_STR_W[] = { '/', '\0' };
static const WCHAR PATH_BACKSLASH_STR_W[] = { '\\', '\0' };
#endif
#endif
#ifdef _WIN32
#define PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
#define PATH_SEPARATOR_STR PATH_BACKSLASH_STR
#define PATH_SEPARATOR_CHR_W PATH_BACKSLASH_CHR_W
#define PATH_SEPARATOR_STR_W PATH_BACKSLASH_STR_W
#else
#define PATH_SEPARATOR_CHR PATH_SLASH_CHR
#define PATH_SEPARATOR_STR PATH_SLASH_STR
#define PATH_SEPARATOR_CHR_W PATH_SLASH_CHR_W
#define PATH_SEPARATOR_STR_W PATH_SLASH_STR_W
#endif
#include "../log.h"
#define TAG WINPR_TAG("path")
/*
* PathCchAddBackslash
*/
/* Windows-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
#define PATH_CCH_ADD_SEPARATOR PathCchAddBackslashA
#include "include/PathCchAddSeparator.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_SEPARATOR
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR_W
#define PATH_CCH_ADD_SEPARATOR PathCchAddBackslashW
#include "include/PathCchAddSeparator.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_SEPARATOR
/* Unix-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
#define PATH_CCH_ADD_SEPARATOR PathCchAddSlashA
#include "include/PathCchAddSeparator.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_SEPARATOR
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR_W
#define PATH_CCH_ADD_SEPARATOR PathCchAddSlashW
#include "include/PathCchAddSeparator.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_SEPARATOR
/* Native-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
#define PATH_CCH_ADD_SEPARATOR PathCchAddSeparatorA
#include "include/PathCchAddSeparator.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_SEPARATOR
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR_W
#define PATH_CCH_ADD_SEPARATOR PathCchAddSeparatorW
#include "include/PathCchAddSeparator.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_SEPARATOR
/*
* PathCchRemoveBackslash
*/
HRESULT PathCchRemoveBackslashA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
HRESULT PathCchRemoveBackslashW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
/*
* PathCchAddBackslashEx
*/
/* Windows-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddBackslashExA
#include "include/PathCchAddSeparatorEx.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_SEPARATOR_EX
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR_W
#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddBackslashExW
#include "include/PathCchAddSeparatorEx.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_SEPARATOR_EX
/* Unix-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSlashExA
#include "include/PathCchAddSeparatorEx.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_SEPARATOR_EX
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR_W
#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSlashExW
#include "include/PathCchAddSeparatorEx.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_SEPARATOR_EX
/* Native-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSeparatorExA
#include "include/PathCchAddSeparatorEx.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_SEPARATOR_EX
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR_W
#define PATH_CCH_ADD_SEPARATOR_EX PathCchAddSeparatorExW
#include "include/PathCchAddSeparatorEx.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_SEPARATOR_EX
HRESULT PathCchRemoveBackslashExA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
WINPR_ATTR_UNUSED PSTR* ppszEnd,
WINPR_ATTR_UNUSED size_t* pcchRemaining)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
HRESULT PathCchRemoveBackslashExW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
WINPR_ATTR_UNUSED PWSTR* ppszEnd,
WINPR_ATTR_UNUSED size_t* pcchRemaining)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
/*
* PathCchAddExtension
*/
/* Windows-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
#define PATH_CCH_ADD_EXTENSION PathCchAddExtensionA
#include "include/PathCchAddExtension.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_EXTENSION
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR_W
#define PATH_CCH_ADD_EXTENSION PathCchAddExtensionW
#include "include/PathCchAddExtension.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_EXTENSION
/* Unix-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
#define PATH_CCH_ADD_EXTENSION UnixPathCchAddExtensionA
#include "include/PathCchAddExtension.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_EXTENSION
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR_W
#define PATH_CCH_ADD_EXTENSION UnixPathCchAddExtensionW
#include "include/PathCchAddExtension.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_EXTENSION
/* Native-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
#define PATH_CCH_ADD_EXTENSION NativePathCchAddExtensionA
#include "include/PathCchAddExtension.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_EXTENSION
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR_W
#define PATH_CCH_ADD_EXTENSION NativePathCchAddExtensionW
#include "include/PathCchAddExtension.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef PATH_CCH_ADD_EXTENSION
/*
* PathCchAppend
*/
/* Windows-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR
#define PATH_CCH_APPEND PathCchAppendA
#include "include/PathCchAppend.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef CUR_PATH_SEPARATOR_STR
#undef PATH_CCH_APPEND
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR_W
#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR_W
#define PATH_CCH_APPEND PathCchAppendW
#include "include/PathCchAppend.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef CUR_PATH_SEPARATOR_STR
#undef PATH_CCH_APPEND
/* Unix-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR
#define PATH_CCH_APPEND UnixPathCchAppendA
#include "include/PathCchAppend.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef CUR_PATH_SEPARATOR_STR
#undef PATH_CCH_APPEND
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR_W
#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR_W
#define PATH_CCH_APPEND UnixPathCchAppendW
#include "include/PathCchAppend.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef CUR_PATH_SEPARATOR_STR
#undef PATH_CCH_APPEND
/* Native-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR
#define PATH_CCH_APPEND NativePathCchAppendA
#include "include/PathCchAppend.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef CUR_PATH_SEPARATOR_STR
#undef PATH_CCH_APPEND
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR_W
#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR_W
#define PATH_CCH_APPEND NativePathCchAppendW
#include "include/PathCchAppend.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef CUR_PATH_SEPARATOR_STR
#undef PATH_CCH_APPEND
/*
* PathCchAppendEx
*/
HRESULT PathCchAppendExA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
WINPR_ATTR_UNUSED PCSTR pszMore, WINPR_ATTR_UNUSED unsigned long dwFlags)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
HRESULT PathCchAppendExW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
WINPR_ATTR_UNUSED PCWSTR pszMore, WINPR_ATTR_UNUSED unsigned long dwFlags)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
/*
* PathCchCanonicalize
*/
HRESULT PathCchCanonicalizeA(WINPR_ATTR_UNUSED PSTR pszPathOut, WINPR_ATTR_UNUSED size_t cchPathOut,
WINPR_ATTR_UNUSED PCSTR pszPathIn)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
HRESULT PathCchCanonicalizeW(WINPR_ATTR_UNUSED PWSTR pszPathOut,
WINPR_ATTR_UNUSED size_t cchPathOut,
WINPR_ATTR_UNUSED PCWSTR pszPathIn)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
/*
* PathCchCanonicalizeEx
*/
HRESULT PathCchCanonicalizeExA(WINPR_ATTR_UNUSED PSTR pszPathOut,
WINPR_ATTR_UNUSED size_t cchPathOut,
WINPR_ATTR_UNUSED PCSTR pszPathIn,
WINPR_ATTR_UNUSED unsigned long dwFlags)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
HRESULT PathCchCanonicalizeExW(WINPR_ATTR_UNUSED PWSTR pszPathOut,
WINPR_ATTR_UNUSED size_t cchPathOut,
WINPR_ATTR_UNUSED PCWSTR pszPathIn,
WINPR_ATTR_UNUSED unsigned long dwFlags)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
/*
* PathAllocCanonicalize
*/
HRESULT PathAllocCanonicalizeA(WINPR_ATTR_UNUSED PCSTR pszPathIn,
WINPR_ATTR_UNUSED unsigned long dwFlags,
WINPR_ATTR_UNUSED PSTR* ppszPathOut)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
HRESULT PathAllocCanonicalizeW(WINPR_ATTR_UNUSED PCWSTR pszPathIn,
WINPR_ATTR_UNUSED unsigned long dwFlags,
WINPR_ATTR_UNUSED PWSTR* ppszPathOut)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
/*
* PathCchCombine
*/
HRESULT PathCchCombineA(WINPR_ATTR_UNUSED PSTR pszPathOut, WINPR_ATTR_UNUSED size_t cchPathOut,
WINPR_ATTR_UNUSED PCSTR pszPathIn, WINPR_ATTR_UNUSED PCSTR pszMore)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
HRESULT PathCchCombineW(WINPR_ATTR_UNUSED PWSTR pszPathOut, WINPR_ATTR_UNUSED size_t cchPathOut,
WINPR_ATTR_UNUSED PCWSTR pszPathIn, WINPR_ATTR_UNUSED PCWSTR pszMore)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
/*
* PathCchCombineEx
*/
HRESULT PathCchCombineExA(WINPR_ATTR_UNUSED PSTR pszPathOut, WINPR_ATTR_UNUSED size_t cchPathOut,
WINPR_ATTR_UNUSED PCSTR pszPathIn, WINPR_ATTR_UNUSED PCSTR pszMore,
WINPR_ATTR_UNUSED unsigned long dwFlags)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
HRESULT PathCchCombineExW(WINPR_ATTR_UNUSED PWSTR pszPathOut, WINPR_ATTR_UNUSED size_t cchPathOut,
WINPR_ATTR_UNUSED PCWSTR pszPathIn, WINPR_ATTR_UNUSED PCWSTR pszMore,
WINPR_ATTR_UNUSED unsigned long dwFlags)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
/*
* PathAllocCombine
*/
/* Windows-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR
#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR
#define PATH_ALLOC_COMBINE PathAllocCombineA
#include "include/PathAllocCombine.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef CUR_PATH_SEPARATOR_STR
#undef PATH_ALLOC_COMBINE
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_BACKSLASH_CHR_W
#define CUR_PATH_SEPARATOR_STR PATH_BACKSLASH_STR_W
#define PATH_ALLOC_COMBINE PathAllocCombineW
#include "include/PathAllocCombine.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef CUR_PATH_SEPARATOR_STR
#undef PATH_ALLOC_COMBINE
/* Unix-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR
#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR
#define PATH_ALLOC_COMBINE UnixPathAllocCombineA
#include "include/PathAllocCombine.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef CUR_PATH_SEPARATOR_STR
#undef PATH_ALLOC_COMBINE
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_SLASH_CHR_W
#define CUR_PATH_SEPARATOR_STR PATH_SLASH_STR_W
#define PATH_ALLOC_COMBINE UnixPathAllocCombineW
#include "include/PathAllocCombine.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef CUR_PATH_SEPARATOR_STR
#undef PATH_ALLOC_COMBINE
/* Native-style Paths */
#define DEFINE_UNICODE FALSE
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR
#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR
#define PATH_ALLOC_COMBINE NativePathAllocCombineA
#include "include/PathAllocCombine.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef CUR_PATH_SEPARATOR_STR
#undef PATH_ALLOC_COMBINE
#define DEFINE_UNICODE TRUE
#define CUR_PATH_SEPARATOR_CHR PATH_SEPARATOR_CHR_W
#define CUR_PATH_SEPARATOR_STR PATH_SEPARATOR_STR_W
#define PATH_ALLOC_COMBINE NativePathAllocCombineW
#include "include/PathAllocCombine.h"
#undef DEFINE_UNICODE
#undef CUR_PATH_SEPARATOR_CHR
#undef CUR_PATH_SEPARATOR_STR
#undef PATH_ALLOC_COMBINE
/**
* PathCchFindExtension
*/
HRESULT PathCchFindExtensionA(PCSTR pszPath, size_t cchPath, PCSTR* ppszExt)
{
const char* p = (const char*)pszPath;
if (!pszPath || !cchPath || !ppszExt)
return E_INVALIDARG;
/* find end of string */
while (*p && --cchPath)
{
p++;
}
if (*p)
{
/* pszPath is not null terminated within the cchPath range */
return E_INVALIDARG;
}
/* If no extension is found, ppszExt must point to the string's terminating null */
*ppszExt = p;
/* search backwards for '.' */
while (p > pszPath)
{
if (*p == '.')
{
*ppszExt = (PCSTR)p;
break;
}
if ((*p == '\\') || (*p == '/') || (*p == ':'))
break;
p--;
}
return S_OK;
}
HRESULT PathCchFindExtensionW(WINPR_ATTR_UNUSED PCWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
WINPR_ATTR_UNUSED PCWSTR* ppszExt)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
/**
* PathCchRenameExtension
*/
HRESULT PathCchRenameExtensionA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
WINPR_ATTR_UNUSED PCSTR pszExt)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
HRESULT PathCchRenameExtensionW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath,
WINPR_ATTR_UNUSED PCWSTR pszExt)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
/**
* PathCchRemoveExtension
*/
HRESULT PathCchRemoveExtensionA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
HRESULT PathCchRemoveExtensionW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
/**
* PathCchIsRoot
*/
BOOL PathCchIsRootA(WINPR_ATTR_UNUSED PCSTR pszPath)
{
WLog_ERR(TAG, "not implemented");
return FALSE;
}
BOOL PathCchIsRootW(WINPR_ATTR_UNUSED PCWSTR pszPath)
{
WLog_ERR(TAG, "not implemented");
return FALSE;
}
/**
* PathIsUNCEx
*/
BOOL PathIsUNCExA(PCSTR pszPath, PCSTR* ppszServer)
{
if (!pszPath)
return FALSE;
if ((pszPath[0] == '\\') && (pszPath[1] == '\\'))
{
*ppszServer = &pszPath[2];
return TRUE;
}
return FALSE;
}
BOOL PathIsUNCExW(PCWSTR pszPath, PCWSTR* ppszServer)
{
if (!pszPath)
return FALSE;
if ((pszPath[0] == '\\') && (pszPath[1] == '\\'))
{
*ppszServer = &pszPath[2];
return TRUE;
}
return FALSE;
}
/**
* PathCchSkipRoot
*/
HRESULT PathCchSkipRootA(WINPR_ATTR_UNUSED PCSTR pszPath, WINPR_ATTR_UNUSED PCSTR* ppszRootEnd)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
HRESULT PathCchSkipRootW(WINPR_ATTR_UNUSED PCWSTR pszPath, WINPR_ATTR_UNUSED PCWSTR* ppszRootEnd)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
/**
* PathCchStripToRoot
*/
HRESULT PathCchStripToRootA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
HRESULT PathCchStripToRootW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
/**
* PathCchStripPrefix
*/
HRESULT PathCchStripPrefixA(PSTR pszPath, size_t cchPath)
{
BOOL hasPrefix = 0;
if (!pszPath)
return E_INVALIDARG;
if (cchPath < 4 || cchPath > PATHCCH_MAX_CCH)
return E_INVALIDARG;
hasPrefix = ((pszPath[0] == '\\') && (pszPath[1] == '\\') && (pszPath[2] == '?') &&
(pszPath[3] == '\\'));
if (hasPrefix)
{
if (cchPath < 6)
return S_FALSE;
if (IsCharAlpha(pszPath[4]) && (pszPath[5] == ':')) /* like C: */
{
memmove_s(pszPath, cchPath, &pszPath[4], cchPath - 4);
/* since the passed pszPath must not necessarily be null terminated
* and we always have enough space after the strip we can always
* ensure the null termination of the stripped result
*/
pszPath[cchPath - 4] = 0;
return S_OK;
}
}
return S_FALSE;
}
HRESULT PathCchStripPrefixW(PWSTR pszPath, size_t cchPath)
{
BOOL hasPrefix = 0;
if (!pszPath)
return E_INVALIDARG;
if (cchPath < 4 || cchPath > PATHCCH_MAX_CCH)
return E_INVALIDARG;
hasPrefix = ((pszPath[0] == '\\') && (pszPath[1] == '\\') && (pszPath[2] == '?') &&
(pszPath[3] == '\\'));
if (hasPrefix)
{
if (cchPath < 6)
return S_FALSE;
const size_t rc = (_wcslen(&pszPath[4]) + 1);
if (cchPath < rc)
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
if (IsCharAlphaW(pszPath[4]) && (pszPath[5] == L':')) /* like C: */
{
wmemmove_s(pszPath, cchPath, &pszPath[4], cchPath - 4);
/* since the passed pszPath must not necessarily be null terminated
* and we always have enough space after the strip we can always
* ensure the null termination of the stripped result
*/
pszPath[cchPath - 4] = 0;
return S_OK;
}
}
return S_FALSE;
}
/**
* PathCchRemoveFileSpec
*/
HRESULT PathCchRemoveFileSpecA(WINPR_ATTR_UNUSED PSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
HRESULT PathCchRemoveFileSpecW(WINPR_ATTR_UNUSED PWSTR pszPath, WINPR_ATTR_UNUSED size_t cchPath)
{
WLog_ERR(TAG, "not implemented");
return E_NOTIMPL;
}
/*
* Path Portability Functions
*/
/**
* PathCchConvertStyle
*/
HRESULT PathCchConvertStyleA(PSTR pszPath, size_t cchPath, unsigned long dwFlags)
{
if (dwFlags == PATH_STYLE_WINDOWS)
{
for (size_t index = 0; index < cchPath; index++)
{
if (pszPath[index] == PATH_SLASH_CHR)
pszPath[index] = PATH_BACKSLASH_CHR;
}
}
else if (dwFlags == PATH_STYLE_UNIX)
{
for (size_t index = 0; index < cchPath; index++)
{
if (pszPath[index] == PATH_BACKSLASH_CHR)
pszPath[index] = PATH_SLASH_CHR;
}
}
else if (dwFlags == PATH_STYLE_NATIVE)
{
if (PATH_SEPARATOR_CHR == PATH_BACKSLASH_CHR)
{
/* Unix-style to Windows-style */
for (size_t index = 0; index < cchPath; index++)
{
if (pszPath[index] == PATH_SLASH_CHR)
pszPath[index] = PATH_BACKSLASH_CHR;
}
}
else if (PATH_SEPARATOR_CHR == PATH_SLASH_CHR)
{
/* Windows-style to Unix-style */
for (size_t index = 0; index < cchPath; index++)
{
if (pszPath[index] == PATH_BACKSLASH_CHR)
pszPath[index] = PATH_SLASH_CHR;
}
}
else
{
/* Unexpected error */
return E_FAIL;
}
}
else
{
/* Gangnam style? */
return E_FAIL;
}
return S_OK;
}
HRESULT PathCchConvertStyleW(PWSTR pszPath, size_t cchPath, unsigned long dwFlags)
{
if (dwFlags == PATH_STYLE_WINDOWS)
{
for (size_t index = 0; index < cchPath; index++)
{
if (pszPath[index] == PATH_SLASH_CHR_W)
pszPath[index] = PATH_BACKSLASH_CHR_W;
}
}
else if (dwFlags == PATH_STYLE_UNIX)
{
for (size_t index = 0; index < cchPath; index++)
{
if (pszPath[index] == PATH_BACKSLASH_CHR_W)
pszPath[index] = PATH_SLASH_CHR_W;
}
}
else if (dwFlags == PATH_STYLE_NATIVE)
{
if (PATH_SEPARATOR_CHR == PATH_BACKSLASH_CHR_W)
{
/* Unix-style to Windows-style */
for (size_t index = 0; index < cchPath; index++)
{
if (pszPath[index] == PATH_SLASH_CHR_W)
pszPath[index] = PATH_BACKSLASH_CHR_W;
}
}
else if (PATH_SEPARATOR_CHR == PATH_SLASH_CHR_W)
{
/* Windows-style to Unix-style */
for (size_t index = 0; index < cchPath; index++)
{
if (pszPath[index] == PATH_BACKSLASH_CHR_W)
pszPath[index] = PATH_SLASH_CHR_W;
}
}
else
{
/* Unexpected error */
return E_FAIL;
}
}
else
{
/* Gangnam style? */
return E_FAIL;
}
return S_OK;
}
/**
* PathGetSeparator
*/
char PathGetSeparatorA(unsigned long dwFlags)
{
char separator = PATH_SEPARATOR_CHR;
if (!dwFlags)
dwFlags = PATH_STYLE_NATIVE;
if (dwFlags == PATH_STYLE_WINDOWS)
separator = PATH_SEPARATOR_CHR;
else if (dwFlags == PATH_STYLE_UNIX)
separator = PATH_SEPARATOR_CHR;
else if (dwFlags == PATH_STYLE_NATIVE)
separator = PATH_SEPARATOR_CHR;
return separator;
}
WCHAR PathGetSeparatorW(unsigned long dwFlags)
{
union
{
WCHAR w;
char c[2];
} cnv;
cnv.c[0] = PATH_SEPARATOR_CHR;
cnv.c[1] = '\0';
if (!dwFlags)
dwFlags = PATH_STYLE_NATIVE;
if (dwFlags == PATH_STYLE_WINDOWS)
cnv.c[0] = PATH_SEPARATOR_CHR;
else if (dwFlags == PATH_STYLE_UNIX)
cnv.c[0] = PATH_SEPARATOR_CHR;
else if (dwFlags == PATH_STYLE_NATIVE)
cnv.c[0] = PATH_SEPARATOR_CHR;
return cnv.w;
}
/**
* PathGetSharedLibraryExtension
*/
static const CHAR SharedLibraryExtensionDllA[] = "dll";
static const CHAR SharedLibraryExtensionSoA[] = "so";
static const CHAR SharedLibraryExtensionDylibA[] = "dylib";
static const CHAR SharedLibraryExtensionDotDllA[] = ".dll";
static const CHAR SharedLibraryExtensionDotSoA[] = ".so";
static const CHAR SharedLibraryExtensionDotDylibA[] = ".dylib";
PCSTR PathGetSharedLibraryExtensionA(unsigned long dwFlags)
{
if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT)
{
if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
{
if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
return SharedLibraryExtensionDotDllA;
if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
return SharedLibraryExtensionDotSoA;
if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
return SharedLibraryExtensionDotDylibA;
}
else
{
if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
return SharedLibraryExtensionDllA;
if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
return SharedLibraryExtensionSoA;
if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
return SharedLibraryExtensionDylibA;
}
}
if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
{
#ifdef _WIN32
return SharedLibraryExtensionDotDllA;
#elif defined(__APPLE__)
if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
return SharedLibraryExtensionDotSoA;
else
return SharedLibraryExtensionDotDylibA;
#else
return SharedLibraryExtensionDotSoA;
#endif
}
else
{
#ifdef _WIN32
return SharedLibraryExtensionDllA;
#elif defined(__APPLE__)
if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
return SharedLibraryExtensionSoA;
else
return SharedLibraryExtensionDylibA;
#else
return SharedLibraryExtensionSoA;
#endif
}
}
PCWSTR PathGetSharedLibraryExtensionW(unsigned long dwFlags)
{
static WCHAR buffer[6][16] = WINPR_C_ARRAY_INIT;
const WCHAR* SharedLibraryExtensionDotDllW = InitializeConstWCharFromUtf8(
SharedLibraryExtensionDotDllA, buffer[0], ARRAYSIZE(buffer[0]));
const WCHAR* SharedLibraryExtensionDotSoW =
InitializeConstWCharFromUtf8(SharedLibraryExtensionDotSoA, buffer[1], ARRAYSIZE(buffer[1]));
const WCHAR* SharedLibraryExtensionDotDylibW = InitializeConstWCharFromUtf8(
SharedLibraryExtensionDotDylibA, buffer[2], ARRAYSIZE(buffer[2]));
const WCHAR* SharedLibraryExtensionDllW =
InitializeConstWCharFromUtf8(SharedLibraryExtensionDllA, buffer[3], ARRAYSIZE(buffer[3]));
const WCHAR* SharedLibraryExtensionSoW =
InitializeConstWCharFromUtf8(SharedLibraryExtensionSoA, buffer[4], ARRAYSIZE(buffer[4]));
const WCHAR* SharedLibraryExtensionDylibW =
InitializeConstWCharFromUtf8(SharedLibraryExtensionDylibA, buffer[5], ARRAYSIZE(buffer[5]));
if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT)
{
if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
{
if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
return SharedLibraryExtensionDotDllW;
if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
return SharedLibraryExtensionDotSoW;
if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
return SharedLibraryExtensionDotDylibW;
}
else
{
if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DLL)
return SharedLibraryExtensionDllW;
if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_SO)
return SharedLibraryExtensionSoW;
if (dwFlags & PATH_SHARED_LIB_EXT_EXPLICIT_DYLIB)
return SharedLibraryExtensionDylibW;
}
}
if (dwFlags & PATH_SHARED_LIB_EXT_WITH_DOT)
{
#ifdef _WIN32
return SharedLibraryExtensionDotDllW;
#elif defined(__APPLE__)
if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
return SharedLibraryExtensionDotSoW;
else
return SharedLibraryExtensionDotDylibW;
#else
return SharedLibraryExtensionDotSoW;
#endif
}
else
{
#ifdef _WIN32
return SharedLibraryExtensionDllW;
#elif defined(__APPLE__)
if (dwFlags & PATH_SHARED_LIB_EXT_APPLE_SO)
return SharedLibraryExtensionSoW;
else
return SharedLibraryExtensionDylibW;
#else
return SharedLibraryExtensionSoW;
#endif
}
}
const char* GetKnownPathIdString(int id)
{
switch (id)
{
case KNOWN_PATH_HOME:
return "KNOWN_PATH_HOME";
case KNOWN_PATH_TEMP:
return "KNOWN_PATH_TEMP";
case KNOWN_PATH_XDG_DATA_HOME:
return "KNOWN_PATH_XDG_DATA_HOME";
case KNOWN_PATH_XDG_CONFIG_HOME:
return "KNOWN_PATH_XDG_CONFIG_HOME";
case KNOWN_PATH_XDG_CACHE_HOME:
return "KNOWN_PATH_XDG_CACHE_HOME";
case KNOWN_PATH_XDG_RUNTIME_DIR:
return "KNOWN_PATH_XDG_RUNTIME_DIR";
case KNOWN_PATH_SYSTEM_CONFIG_HOME:
return "KNOWN_PATH_SYSTEM_CONFIG_HOME";
default:
return "KNOWN_PATH_UNKNOWN_ID";
}
}
static char* concat(const char* path, size_t pathlen, const char* name, size_t namelen)
{
const size_t strsize = pathlen + namelen + 2;
char* str = calloc(strsize, sizeof(char));
if (!str)
return nullptr;
winpr_str_append(path, str, strsize, "");
winpr_str_append(name, str, strsize, "");
return str;
}
BOOL winpr_RemoveDirectory_RecursiveA(LPCSTR lpPathName)
{
BOOL ret = FALSE;
if (!lpPathName)
return FALSE;
const size_t pathnamelen = strlen(lpPathName);
const size_t path_slash_len = pathnamelen + 3;
char* path_slash = calloc(pathnamelen + 4, sizeof(char));
if (!path_slash)
return FALSE;
strncat(path_slash, lpPathName, pathnamelen);
const char star[] = "*";
const HRESULT hr = NativePathCchAppendA(path_slash, path_slash_len, star);
HANDLE dir = INVALID_HANDLE_VALUE;
if (FAILED(hr))
goto fail;
{
WIN32_FIND_DATAA findFileData = WINPR_C_ARRAY_INIT;
dir = FindFirstFileA(path_slash, &findFileData);
if (dir == INVALID_HANDLE_VALUE)
goto fail;
ret = TRUE;
path_slash[path_slash_len - 1] = '\0'; /* remove trailing '*' */
do
{
const size_t len = strnlen(findFileData.cFileName, ARRAYSIZE(findFileData.cFileName));
if ((len == 1 && findFileData.cFileName[0] == '.') ||
(len == 2 && findFileData.cFileName[0] == '.' && findFileData.cFileName[1] == '.'))
{
continue;
}
char* fullpath = concat(path_slash, path_slash_len, findFileData.cFileName, len);
if (!fullpath)
goto fail;
if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
ret = winpr_RemoveDirectory_RecursiveA(fullpath);
else
{
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_DEPRECATED_DECL
ret = DeleteFileA(fullpath);
WINPR_PRAGMA_DIAG_POP
}
free(fullpath);
if (!ret)
break;
} while (ret && FindNextFileA(dir, &findFileData) != 0);
}
if (ret)
{
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_DEPRECATED_DECL
if (!RemoveDirectoryA(lpPathName))
ret = FALSE;
WINPR_PRAGMA_DIAG_POP
}
fail:
FindClose(dir);
free(path_slash);
return ret;
}
BOOL winpr_RemoveDirectory_RecursiveW(LPCWSTR lpPathName)
{
char* name = ConvertWCharToUtf8Alloc(lpPathName, nullptr);
if (!name)
return FALSE;
const BOOL rc = winpr_RemoveDirectory_RecursiveA(name);
free(name);
return rc;
}
char* winpr_GetConfigFilePathVA(BOOL system, WINPR_FORMAT_ARG const char* filename, va_list ap)
{
eKnownPathTypes id = system ? KNOWN_PATH_SYSTEM_CONFIG_HOME : KNOWN_PATH_XDG_CONFIG_HOME;
const char* vendor = winpr_getApplicationDetailsVendor();
const char* product = winpr_getApplicationDetailsProduct();
const SSIZE_T version = winpr_getApplicationDetailsVersion();
if (!vendor || !product)
return nullptr;
char* config = GetKnownSubPathV(id, "%s", vendor);
if (!config)
return nullptr;
char* base = nullptr;
if (version < 0)
base = GetCombinedPathV(config, "%s", product);
else
base = GetCombinedPathV(config, "%s%" PRIdz, product, version);
free(config);
if (!base)
return nullptr;
char* path = GetCombinedPathVA(base, filename, ap);
free(base);
return path;
}
char* winpr_GetConfigFilePath(BOOL system, const char* filename)
{
if (!filename)
return winpr_GetConfigFilePathV(system, "%s", "");
return winpr_GetConfigFilePathV(system, "%s", filename);
}
char* winpr_GetConfigFilePathV(BOOL system, const char* filename, ...)
{
va_list ap = WINPR_C_ARRAY_INIT;
va_start(ap, filename);
char* str = winpr_GetConfigFilePathVA(system, filename, ap);
va_end(ap);
return str;
}