aboutsummaryrefslogtreecommitdiff
path: root/libpkgconf/path.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpkgconf/path.c')
-rw-r--r--libpkgconf/path.c229
1 files changed, 192 insertions, 37 deletions
diff --git a/libpkgconf/path.c b/libpkgconf/path.c
index dda77f5664ab..56d0bb4ddb27 100644
--- a/libpkgconf/path.c
+++ b/libpkgconf/path.c
@@ -2,6 +2,8 @@
* path.c
* filesystem path management
*
+ * SPDX-License-Identifier: pkgconf
+ *
* Copyright (c) 2016 pkgconf authors (see AUTHORS).
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -16,21 +18,18 @@
#include <libpkgconf/config.h>
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
+#include <libpkgconf/path.h>
#if defined(HAVE_SYS_STAT_H) && ! defined(_WIN32)
# include <sys/stat.h>
# define PKGCONF_CACHE_INODES
#endif
-#ifdef _WIN32
-# define PKG_CONFIG_REG_KEY "Software\\pkgconfig\\PKG_CONFIG_PATH"
-#endif
-
static bool
#ifdef PKGCONF_CACHE_INODES
-path_list_contains_entry(const char *text, pkgconf_list_t *dirlist, struct stat *st)
+path_list_contains_entry(const pkgconf_buffer_t *text, pkgconf_list_t *dirlist, struct stat *st)
#else
-path_list_contains_entry(const char *text, pkgconf_list_t *dirlist)
+path_list_contains_entry(const pkgconf_buffer_t *text, pkgconf_list_t *dirlist)
#endif
{
pkgconf_node_t *n;
@@ -44,7 +43,7 @@ path_list_contains_entry(const char *text, pkgconf_list_t *dirlist)
return true;
#endif
- if (!strcmp(text, pn->path))
+ if (!strcmp(pkgconf_buffer_str(text), pn->path))
return true;
}
@@ -66,42 +65,65 @@ static pkgconf_path_t *
prepare_path_node(const char *text, pkgconf_list_t *dirlist, bool filter)
{
pkgconf_path_t *node;
- char path[PKGCONF_ITEM_SIZE];
+ pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER;
- pkgconf_strlcpy(path, text, sizeof path);
- pkgconf_path_relocate(path, sizeof path);
+ pkgconf_buffer_append(&pathbuf, text);
+ pkgconf_path_relocate(&pathbuf);
#ifdef PKGCONF_CACHE_INODES
struct stat st;
if (filter)
{
- if (lstat(path, &st) == -1)
+ if (lstat(pkgconf_buffer_str(&pathbuf), &st) == -1)
+ {
+ pkgconf_buffer_finalize(&pathbuf);
return NULL;
+ }
+
if (S_ISLNK(st.st_mode))
{
- char pathbuf[PKGCONF_ITEM_SIZE * 4];
- char *linkdest = realpath(path, pathbuf);
+ char realpathbuf[PKGCONF_ITEM_SIZE * 4];
+ char *linkdest = realpath(pkgconf_buffer_str(&pathbuf), realpathbuf);
if (linkdest != NULL && stat(linkdest, &st) == -1)
+ {
+ pkgconf_buffer_finalize(&pathbuf);
return NULL;
+ }
}
- if (path_list_contains_entry(path, dirlist, &st))
+
+ if (path_list_contains_entry(&pathbuf, dirlist, &st))
+ {
+ pkgconf_buffer_finalize(&pathbuf);
return NULL;
+ }
}
#else
- if (filter && path_list_contains_entry(path, dirlist))
+ if (filter && path_list_contains_entry(&pathbuf, dirlist))
+ {
+ pkgconf_buffer_finalize(&pathbuf);
return NULL;
+ }
#endif
node = calloc(1, sizeof(pkgconf_path_t));
if (node == NULL)
+ {
+ pkgconf_buffer_finalize(&pathbuf);
return NULL;
+ }
- node->path = strdup(path);
+ node->path = pkgconf_buffer_freeze(&pathbuf);
+ if (node->path == NULL)
+ {
+ free(node);
+ return NULL;
+ }
#ifdef PKGCONF_CACHE_INODES
- if (filter) {
+ if (filter)
+ {
node->handle_path = (void *)(intptr_t) st.st_ino;
node->handle_device = (void *)(intptr_t) st.st_dev;
}
@@ -177,6 +199,9 @@ pkgconf_path_split(const char *text, pkgconf_list_t *dirlist, bool filter)
return 0;
iter = workbuf = strdup(text);
+ if (workbuf == NULL)
+ return 0;
+
while ((p = strtok(iter, PKG_CONFIG_PATH_SEP_S)) != NULL)
{
pkgconf_path_add(p, dirlist, filter);
@@ -196,6 +221,7 @@ pkgconf_path_split(const char *text, pkgconf_list_t *dirlist, bool filter)
* Adds the paths specified in an environment variable to a path list. If the environment variable is not set,
* an optional default set of paths is added.
*
+ * :param pkgconf_client_t* client: The client to use for environmental variable lookup (can be NULL).
* :param char* envvarname: The environment variable to look up.
* :param char* fallback: The fallback paths to use if the environment variable is not set.
* :param pkgconf_list_t* dirlist: The path list to add the path nodes to.
@@ -204,11 +230,11 @@ pkgconf_path_split(const char *text, pkgconf_list_t *dirlist, bool filter)
* :rtype: size_t
*/
size_t
-pkgconf_path_build_from_environ(const char *envvarname, const char *fallback, pkgconf_list_t *dirlist, bool filter)
+pkgconf_path_build_from_environ(const pkgconf_client_t *client, const char *envvarname, const char *fallback, pkgconf_list_t *dirlist, bool filter)
{
const char *data;
- data = getenv(envvarname);
+ data = pkgconf_client_getenv(client, envvarname);
if (data != NULL)
return pkgconf_path_split(data, dirlist, filter);
@@ -235,21 +261,36 @@ bool
pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist)
{
pkgconf_node_t *n = NULL;
- char relocated[PKGCONF_ITEM_SIZE];
+ pkgconf_buffer_t relocated = PKGCONF_BUFFER_INITIALIZER;
const char *cpath = path;
- pkgconf_strlcpy(relocated, path, sizeof relocated);
- if (pkgconf_path_relocate(relocated, sizeof relocated))
- cpath = relocated;
+ if (path == NULL)
+ return false;
+
+ pkgconf_buffer_append(&relocated, path);
+ cpath = pkgconf_buffer_str(&relocated);
+
+ if (pkgconf_path_relocate(&relocated))
+ cpath = pkgconf_buffer_str(&relocated);
+
+ if (cpath == NULL)
+ {
+ pkgconf_buffer_finalize(&relocated);
+ return false;
+ }
PKGCONF_FOREACH_LIST_ENTRY(dirlist->head, n)
{
pkgconf_path_t *pnode = n->data;
if (!strcmp(pnode->path, cpath))
+ {
+ pkgconf_buffer_finalize(&relocated);
return true;
+ }
}
+ pkgconf_buffer_finalize(&relocated);
return false;
}
@@ -278,6 +319,11 @@ pkgconf_path_copy_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
continue;
path->path = strdup(srcpath->path);
+ if (path->path == NULL)
+ {
+ free(path);
+ continue;
+ }
#ifdef PKGCONF_CACHE_INODES
path->handle_path = srcpath->handle_path;
@@ -313,6 +359,11 @@ pkgconf_path_prepend_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
continue;
path->path = strdup(srcpath->path);
+ if (path->path == NULL)
+ {
+ free(path);
+ continue;
+ }
#ifdef PKGCONF_CACHE_INODES
path->handle_path = srcpath->handle_path;
@@ -350,11 +401,12 @@ pkgconf_path_free(pkgconf_list_t *dirlist)
}
static char *
-normpath(const char *path)
+normpath(const pkgconf_buffer_t *pathbuf)
{
- if (!path)
+ if (!pathbuf || pkgconf_buffer_len(pathbuf) == 0)
return NULL;
+ const char *path = pkgconf_buffer_str(pathbuf);
char *copy = strdup(path);
if (NULL == copy)
return NULL;
@@ -379,37 +431,96 @@ normpath(const char *path)
/*
* !doc
*
- * .. c:function:: bool pkgconf_path_relocate(char *buf, size_t buflen)
+ * .. c:function:: bool pkgconf_path_relocate(pkgconf_buffer_t *buf)
*
* Relocates a path, possibly calling normpath() on it.
*
- * :param char* buf: The path to relocate.
- * :param size_t buflen: The buffer length the path is contained in.
+ * :param pkgconf_buffer_t* buf: The path to relocate.
* :return: true on success, false on error
* :rtype: bool
*/
bool
-pkgconf_path_relocate(char *buf, size_t buflen)
+pkgconf_path_relocate(pkgconf_buffer_t *buf)
{
char *tmpbuf;
if ((tmpbuf = normpath(buf)) != NULL)
{
- size_t tmpbuflen = strlen(tmpbuf);
- if (tmpbuflen > buflen)
- {
- free(tmpbuf);
- return false;
- }
-
- pkgconf_strlcpy(buf, tmpbuf, buflen);
+ pkgconf_buffer_reset(buf);
+ pkgconf_buffer_append(buf, tmpbuf);
free(tmpbuf);
}
return true;
}
+/*
+ * !doc
+ *
+ * .. c:function:: bool pkgconf_path_trim_basename(pkgconf_buffer_t *buf)
+ *
+ * Trims the basename from a path.
+ *
+ * :param pkgconf_buffer_t* buf: The path to trim.
+ * :return: true if a separator was found and the path was trimmed, false otherwise
+ * :rtype: bool
+ */
+bool
+pkgconf_path_trim_basename(pkgconf_buffer_t *buf)
+{
+ char *sep;
+
+ if (!pkgconf_buffer_len(buf))
+ return false;
+
+ sep = strrchr(buf->base, PKG_DIR_SEP_S);
+#ifdef _WIN32
+ char *sep2 = strrchr(buf->base, '/');
+ if (sep2 != NULL && (sep == NULL || sep2 > sep))
+ sep = sep2;
+#endif
+
+ if (sep != NULL)
+ {
+ *sep = '\0';
+ buf->end = sep;
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * !doc
+ *
+ * .. c:function:: const char *pkgconf_path_find_basename(const char *path)
+ *
+ * Finds the basename from a path.
+ *
+ * :param char* path: The path to find the basename from.
+ * :return: a pointer to the basename
+ * :rtype: const char *
+ */
+const char *
+pkgconf_path_find_basename(const char *path)
+{
+ const char *sep;
+
+ sep = strrchr(path, PKG_DIR_SEP_S);
+#ifdef _WIN32
+ const char *sep2 = strrchr(path, '/');
+ if (sep2 != NULL && (sep == NULL || sep2 > sep))
+ sep = sep2;
+#endif
+
+ if (sep != NULL)
+ return sep + 1;
+
+ return path;
+}
+
#ifdef _WIN32
+#define PKG_CONFIG_REG_KEY "Software\\pkgconfig\\PKG_CONFIG_PATH"
/*
* !doc
*
@@ -457,3 +568,47 @@ pkgconf_path_build_from_registry(void *hKey, pkgconf_list_t *dir_list, bool filt
return added;
}
#endif
+
+bool
+pkgconf_path_is_plausible(const pkgconf_buffer_t *buf)
+{
+ const char *s;
+
+ if (buf == NULL)
+ return false;
+
+ s = pkgconf_buffer_str(buf);
+ if (s == NULL)
+ return false;
+
+ /* skip leading whitespace */
+ while (*s != '\0' && isspace((unsigned char)*s))
+ s++;
+
+ if (*s == '\0')
+ return false;
+
+ /* POSIX absolute path */
+ if (*s == '/')
+ return true;
+
+ /* ./ or ../ relative path */
+ if (s[0] == '.' && (s[1] == '/' || s[1] == '\\'))
+ return true;
+
+ if (s[0] == '.' && s[1] == '.' && (s[2] == '/' || s[2] == '\\'))
+ return true;
+
+ /* Windows drive path: C:/... or C:\... */
+ if (isalpha((unsigned char)s[0]) && s[1] == ':' && (s[2] == '/' || s[2] == '\\'))
+ return true;
+
+ /* anything with a path separator seems plausible, for example "Program Files/MySDK" */
+ for (const char *p = s; *p != '\0'; p++)
+ {
+ if (*p == '/' || *p == '\\')
+ return true;
+ }
+
+ return false;
+}