From 81d6ed27845be82ae2c339ca74fc0e337d906541 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 29 Jan 2026 09:56:17 +0100 Subject: [PATCH] [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. --- winpr/include/winpr/path.h | 118 ++++++++++++++++++++++++++++++++++++ winpr/libwinpr/path/path.c | 53 ++++++++++------ winpr/libwinpr/path/shell.c | 80 ++++++++++++++++++++---- 3 files changed, 222 insertions(+), 29 deletions(-) diff --git a/winpr/include/winpr/path.h b/winpr/include/winpr/path.h index 7d2878728..620cb4934 100644 --- a/winpr/include/winpr/path.h +++ b/winpr/include/winpr/path.h @@ -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); diff --git a/winpr/libwinpr/path/path.c b/winpr/libwinpr/path/path.c index 6cca837af..34a6fa0bf 100644 --- a/winpr/libwinpr/path/path.c +++ b/winpr/libwinpr/path/path.c @@ -27,6 +27,8 @@ #include #include +#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; +} diff --git a/winpr/libwinpr/path/shell.c b/winpr/libwinpr/path/shell.c index f647e8f08..c5b3ff1ae 100644 --- a/winpr/libwinpr/path/shell.c +++ b/winpr/libwinpr/path/shell.c @@ -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;