[winpr,path] modify GetCombinedPath

Allow the subPath argument to be a format string with variadic
arguments. This allows to generate a subPath on the fly. This change is
API compatible.
This commit is contained in:
Armin Novak
2026-01-29 09:56:17 +01:00
committed by akallabeth
parent 1825fa8214
commit 81d6ed2784
3 changed files with 222 additions and 29 deletions

View File

@@ -326,6 +326,37 @@ extern "C"
WINPR_ATTR_NODISCARD
WINPR_API char* winpr_GetConfigFilePath(BOOL system, const char* filename);
/** @brief Get a config file sub path with a formatting argument constructing the filename
*
* @param system \b TRUE to return a system config path
* @param filename The format string to generate the filename. Must not be \b NULL. Must not
* contain any forbidden characters.
*
* @return A (absolute) configuration file path or \b NULL in case of failure.
* @since version 3.23.0
*/
WINPR_ATTR_MALLOC(free, 1)
WINPR_ATTR_NODISCARD
WINPR_ATTR_FORMAT_ARG(2, 3)
WINPR_API char* winpr_GetConfigFilePathV(BOOL system, WINPR_FORMAT_ARG const char* filename,
...);
/** @brief Get a config file sub path with a formatting argument constructing the filename
*
* @param system \b TRUE to return a system config path
* @param filename The format string to generate the filename. Must not be \b NULL. Must not
* contain any forbidden characters.
* @param ap The argument list
*
* @return A (absolute) configuration file path or \b NULL in case of failure.
* @since version 3.23.0
*/
WINPR_ATTR_MALLOC(free, 1)
WINPR_ATTR_NODISCARD
WINPR_ATTR_FORMAT_ARG(2, 0)
WINPR_API char* winpr_GetConfigFilePathVA(BOOL system, WINPR_FORMAT_ARG const char* filename,
va_list ap);
WINPR_API const char* GetKnownPathIdString(int id);
WINPR_ATTR_MALLOC(free, 1)
@@ -336,6 +367,33 @@ extern "C"
WINPR_ATTR_NODISCARD
WINPR_API char* GetKnownSubPath(eKnownPathTypes id, const char* path);
/** @brief Append a path to some existing known path type.
*
* @param id a \ref eKnownPathTypes known path id
* @param path the format string generating the subpath. Must not be \b NULL
*
* @return A string of combined \b id path and \b path or \b NULL in case of an error.
* @since version 3.23.0
*/
WINPR_ATTR_MALLOC(free, 1)
WINPR_ATTR_NODISCARD
WINPR_ATTR_FORMAT_ARG(2, 3)
WINPR_API char* GetKnownSubPathV(eKnownPathTypes id, const char* path, ...);
/** @brief Append a path to some existing known path type.
*
* @param id a \ref eKnownPathTypes known path id
* @param path the format string generating the subpath. Must not be \b NULL
* @param ap a va_list containing the format string arguments
* * @return A string of combined \b basePath and \b path or \b NULL in case of an
* error.
* * @version since 3.23.0
*/
WINPR_ATTR_MALLOC(free, 1)
WINPR_ATTR_NODISCARD
WINPR_ATTR_FORMAT_ARG(2, 0)
WINPR_API char* GetKnownSubPathVA(eKnownPathTypes id, const char* path, va_list ap);
WINPR_ATTR_MALLOC(free, 1)
WINPR_ATTR_NODISCARD
WINPR_API char* GetEnvironmentPath(char* name);
@@ -344,10 +402,70 @@ extern "C"
WINPR_ATTR_NODISCARD
WINPR_API char* GetEnvironmentSubPath(char* name, const char* path);
/** @brief Append a path to some existing environment name.
*
* @param name The prefix path to use, must not be \b NULL
* @param path A format string used to generate the path to append. Must not be \b NULL
*
* @return A string of combined \b basePath and \b path or \b NULL in case of an error.
* @version since 3.23.0
*/
WINPR_ATTR_MALLOC(free, 1)
WINPR_ATTR_NODISCARD
WINPR_ATTR_FORMAT_ARG(2, 3)
WINPR_API char* GetEnvironmentSubPathV(char* name, WINPR_FORMAT_ARG const char* path, ...);
/** @brief Append a path to some existing environment name.
*
* @param name The prefix path to use, must not be \b NULL
* @param path A format string used to generate the path to append. Must not be \b NULL
* @param ap a va_list containing the format string arguments
*
* @return A string of combined \b basePath and \b path or \b NULL in case of an error.
* * @version since 3.23.0
*/
WINPR_ATTR_MALLOC(free, 1)
WINPR_ATTR_NODISCARD
WINPR_ATTR_FORMAT_ARG(2, 0)
WINPR_API char* GetEnvironmentSubPathVA(char* name, WINPR_FORMAT_ARG const char* path,
va_list ap);
WINPR_ATTR_MALLOC(free, 1)
WINPR_ATTR_NODISCARD
WINPR_API char* GetCombinedPath(const char* basePath, const char* subPath);
/** @brief Append a path to some existing path. A system dependent path separator will be added
* automatically.
*
* @bug before version 3.23.0 the function did not allow subPath to be a format string.
*
* @param basePath The prefix path to use, must not be \b NULL
* @param subPathFmt A format string used to generate the path to append. Must not be \b NULL
*
* @return A string of combined \b basePath and \b subPathFmt or \b NULL in case of an error.
*/
WINPR_ATTR_MALLOC(free, 1)
WINPR_ATTR_NODISCARD
WINPR_ATTR_FORMAT_ARG(2, 3)
WINPR_API char* GetCombinedPathV(const char* basePath, WINPR_FORMAT_ARG const char* subPathFmt,
...);
/** @brief Append a path to some existing path. A system dependent path separator will be added
* automatically.
*
* @param basePath The prefix path to use, must not be \b NULL
* @param subPathFmt A format string used to generate the path to append. Must not be \b NULL
* @param ap a va_list containing the format string arguments
*
* @return A string of combined \b basePath and \b subPathFmt or \b NULL in case of an error.
* @version since 3.23.0
*/
WINPR_ATTR_MALLOC(free, 1)
WINPR_ATTR_NODISCARD
WINPR_ATTR_FORMAT_ARG(2, 0)
WINPR_API char* GetCombinedPathVA(const char* basePath, WINPR_FORMAT_ARG const char* subPathFmt,
va_list ap);
WINPR_API BOOL PathMakePathA(LPCSTR path, LPSECURITY_ATTRIBUTES lpAttributes);
WINPR_API BOOL PathMakePathW(LPCWSTR path, LPSECURITY_ATTRIBUTES lpAttributes);

View File

@@ -27,6 +27,8 @@
#include <winpr/path.h>
#include <winpr/file.h>
#include "../utils.h"
#if defined(WITH_RESOURCE_VERSIONING)
#define STR(x) #x
#endif
@@ -1218,32 +1220,47 @@ BOOL winpr_RemoveDirectory_RecursiveW(LPCWSTR lpPathName)
return rc;
}
char* winpr_GetConfigFilePath(BOOL system, const char* filename)
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 defined(WINPR_USE_VENDOR_PRODUCT_CONFIG_DIR)
char* vendor = GetKnownSubPath(id, WINPR_VENDOR_STRING);
if (!vendor)
if (!vendor || !product)
return NULL;
#if defined(WITH_RESOURCE_VERSIONING)
const char* prod = WINPR_PRODUCT_STRING STR(WINPR_VERSION_MAJOR);
#else
const char* prod = WINPR_PRODUCT_STRING;
#endif
char* base = GetCombinedPath(vendor, prod);
free(vendor);
#else
char* base = GetKnownSubPath(id, "winpr");
#endif
char* config = GetKnownSubPathV(id, "%s", vendor);
if (!config)
return NULL;
char* base = NULL;
if (version < 0)
base = GetCombinedPathV(config, "%s", product);
else
base = GetCombinedPathV(config, "%s%" PRIdz, product, version);
free(config);
if (!base)
return NULL;
if (!filename)
return base;
char* path = GetCombinedPath(base, filename);
char* path = GetCombinedPathVA(base, filename, ap);
free(base);
return path;
}
char* winpr_GetConfigFilePath(BOOL system, const char* filename)
{
if (!filename)
return winpr_GetConfigFilePathV(system, "");
return winpr_GetConfigFilePathV(system, "%s", filename);
}
char* winpr_GetConfigFilePathV(BOOL system, const char* filename, ...)
{
va_list ap;
va_start(ap, filename);
char* str = winpr_GetConfigFilePathVA(system, filename, ap);
va_end(ap);
return str;
}

View File

@@ -393,12 +393,29 @@ char* GetKnownPath(eKnownPathTypes id)
}
char* GetKnownSubPath(eKnownPathTypes id, const char* path)
{
if (!path)
return GetKnownSubPathV(id, "");
return GetKnownSubPathV(id, "%s", path);
}
char* GetKnownSubPathV(eKnownPathTypes id, const char* path, ...)
{
va_list ap;
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 NULL;
char* subPath = GetCombinedPath(knownPath, path);
char* subPath = GetCombinedPathVA(knownPath, path, ap);
free(knownPath);
return subPath;
}
@@ -431,19 +448,50 @@ char* GetEnvironmentPath(char* name)
char* GetEnvironmentSubPath(char* name, const char* path)
{
char* env = NULL;
char* subpath = NULL;
env = GetEnvironmentPath(name);
if (!path)
return GetEnvironmentSubPathV(name, "");
return GetEnvironmentSubPathV(name, "%s", path);
}
char* GetEnvironmentSubPathV(char* name, const char* path, ...)
{
va_list ap;
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 NULL;
subpath = GetCombinedPath(env, path);
char* subpath = GetCombinedPathVA(env, path, ap);
free(env);
return subpath;
}
char* GetCombinedPath(const char* basePath, const char* subPath)
char* GetCombinedPath(const char* basePath, const char* subPathFmt)
{
if (!subPathFmt)
return GetCombinedPathV(basePath, "");
return GetCombinedPathV(basePath, "%s", subPathFmt);
}
char* GetCombinedPathV(const char* basePath, const char* subPathFmt, ...)
{
va_list ap;
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 = NULL;
@@ -453,8 +501,20 @@ char* GetCombinedPath(const char* basePath, const char* subPath)
if (basePath)
basePathLength = strlen(basePath);
if (subPath)
subPathLength = strlen(subPath);
bool haveSubPath = subPathFmt && (*subPathFmt != '\0');
if (haveSubPath)
{
const int rc = winpr_vasprintf(&subPathCpy, &subPathLength, subPathFmt, ap);
if (rc < 0)
return NULL;
if (rc == 0)
{
free(subPathCpy);
subPathCpy = NULL;
subPathLength = 0;
haveSubPath = false;
}
}
const size_t length = basePathLength + subPathLength + 1;
char* path = (char*)calloc(1, length + 1);
@@ -468,11 +528,9 @@ char* GetCombinedPath(const char* basePath, const char* subPath)
if (FAILED(PathCchConvertStyleA(path, basePathLength, PATH_STYLE_NATIVE)))
goto fail;
if (!subPath)
if (!haveSubPath)
return path;
subPathCpy = _strdup(subPath);
if (!subPathCpy)
goto fail;