Merge pull request #363 from SoapGentoo/pcfiledir_symlink

`${pcfiledir}` symlink resolving
master
Ariadne Conill 2024-12-09 19:26:05 -08:00 committed by GitHub
commit 5c535171a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 204 additions and 1 deletions

1
.gitignore vendored
View File

@ -73,6 +73,7 @@ core
/tests/provides
/tests/regress
/tests/requires
/tests/symlink
/tests/sysroot
/tests/test_env.sh
/tests/version

View File

@ -107,6 +107,7 @@ EXTRA_DIST = pkg.m4 \
tests/lib1/tuple-quoting.pc \
tests/lib1/empty-tuple.pc \
tests/lib1/orphaned-requires-private.pc \
tests/lib1/pcfiledir.pc \
tests/lib1/sysroot-dir-2.pc \
tests/lib1/sysroot-dir-3.pc \
tests/lib1/sysroot-dir-4.pc \
@ -137,6 +138,7 @@ test_scripts= tests/meson.build \
tests/provides.sh \
tests/regress.sh \
tests/requires.sh \
tests/symlink.sh \
tests/sysroot.sh \
tests/version.sh

View File

@ -17,6 +17,15 @@
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
#ifndef _WIN32
#include <fcntl.h> // open
#include <libgen.h> // basename/dirname
#include <sys/stat.h> // lstat, S_ISLNK
#include <unistd.h> // close, readlinkat
#include <string.h>
#endif
/*
* !doc
*
@ -63,6 +72,65 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg)
char buf[PKGCONF_ITEM_SIZE], *pathbuf;
pkgconf_strlcpy(buf, pkg->filename, sizeof buf);
#ifndef _WIN32
/*
* We want to resolve symlinks, since ${pcfiledir} should point to the
* parent of the file symlinked to.
*/
struct stat path_stat;
while (!lstat(buf, &path_stat) && S_ISLNK(path_stat.st_mode))
{
/*
* Have to split the path into the dir + file components,
* in order to extract the directory file descriptor.
*
* The nomenclature here uses the
*
* ln <source> <target>
*
* model.
*/
char basenamebuf[PKGCONF_ITEM_SIZE];
pkgconf_strlcpy(basenamebuf, buf, sizeof(basenamebuf));
const char* targetfilename = basename(basenamebuf);
char dirnamebuf[PKGCONF_ITEM_SIZE];
pkgconf_strlcpy(dirnamebuf, buf, sizeof(dirnamebuf));
const char* targetdir = dirname(dirnamebuf);
const int dirfd = open(targetdir, O_DIRECTORY);
if (dirfd == -1)
break;
char sourcebuf[PKGCONF_ITEM_SIZE];
ssize_t len = readlinkat(dirfd, targetfilename, sourcebuf, sizeof(sourcebuf) - 1);
close(dirfd);
if (len == -1)
break;
sourcebuf[len] = '\0';
memset(buf, '\0', sizeof buf);
/*
* The logic here can be a bit tricky, so here's a table:
*
* <source> | <target> | result
* -----------------------------------------------------------------------
* /bar (absolute) | foo/link (relative) | /bar (absolute)
* ../bar (relative) | foo/link (relative) | foo/../bar (relative)
* /bar (absolute) | /foo/link (absolute) | /bar (absolute)
* ../bar (relative) | /foo/link (absolute) | /foo/../bar (relative)
*/
if ((sourcebuf[0] != '/') /* absolute path in <source> wins */
&& (strcmp(targetdir, "."))) /* do not prepend "." */
{
pkgconf_strlcat(buf, targetdir, sizeof buf);
pkgconf_strlcat(buf, "/", sizeof buf);
}
pkgconf_strlcat(buf, sourcebuf, sizeof buf);
}
#endif
pathbuf = strrchr(buf, PKG_DIR_SEP_S);
if (pathbuf == NULL)
pathbuf = strrchr(buf, '/');

View File

@ -11,3 +11,4 @@ atf_test_program{name='conflicts'}
atf_test_program{name='version'}
atf_test_program{name='framework'}
atf_test_program{name='provides'}
atf_test_program{name='symlink'}

8
tests/lib1/pcfiledir.pc Normal file
View File

@ -0,0 +1,8 @@
prefix=${pcfiledir}
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: foo
Description: A testing pkg-config file with a ${pcfiledir}
Version: 1.2.3

View File

@ -11,8 +11,9 @@ tests = [
'provides',
'regress',
'requires',
'symlink',
'sysroot',
'version'
'version',
]

122
tests/symlink.sh Executable file
View File

@ -0,0 +1,122 @@
#!/usr/bin/env atf-sh
. $(atf_get_srcdir)/test_env.sh
tests_init \
pcfiledir_symlink_absolute \
pcfiledir_symlink_relative
# - We need to create a temporary subtree, since symlinks are not preserved
# in "make dist".
# - ${srcdir} is relative and since we need to compare paths, we would have
# to portably canonicalize it again, which is hard. Instead, just keep
# the whole thing nested.
pcfiledir_symlink_absolute_body()
{
mkdir -p tmp/child
cp -f "${selfdir}/lib1/pcfiledir.pc" tmp/child/
ln -f -s "${PWD}/tmp/child/pcfiledir.pc" tmp/pcfiledir.pc # absolute
ln -f -s tmp/pcfiledir.pc pcfiledir.pc
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix pcfiledir.pc
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix tmp/pcfiledir.pc
atf_check \
-o inline:"tmp/child\n" \
pkgconf --variable=prefix tmp/child/pcfiledir.pc
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix "${PWD}/pcfiledir.pc"
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix "${PWD}/tmp/pcfiledir.pc"
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix "${PWD}/tmp/child/pcfiledir.pc"
export PKG_CONFIG_PATH="."
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix pcfiledir
export PKG_CONFIG_PATH="${PWD}"
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix pcfiledir
export PKG_CONFIG_PATH="tmp"
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix pcfiledir
export PKG_CONFIG_PATH="${PWD}/tmp"
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix pcfiledir
export PKG_CONFIG_PATH="tmp/child"
atf_check \
-o inline:"tmp/child\n" \
pkgconf --variable=prefix pcfiledir
export PKG_CONFIG_PATH="${PWD}/tmp/child"
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix pcfiledir
}
pcfiledir_symlink_relative_body()
{
mkdir -p tmp/child
cp -f "${selfdir}/lib1/pcfiledir.pc" tmp/child/
ln -f -s child/pcfiledir.pc tmp/pcfiledir.pc # relative
ln -f -s tmp/pcfiledir.pc pcfiledir.pc
atf_check \
-o inline:"tmp/child\n" \
pkgconf --variable=prefix pcfiledir.pc
atf_check \
-o inline:"tmp/child\n" \
pkgconf --variable=prefix tmp/pcfiledir.pc
atf_check \
-o inline:"tmp/child\n" \
pkgconf --variable=prefix tmp/child/pcfiledir.pc
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix "${PWD}/pcfiledir.pc"
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix "${PWD}/tmp/pcfiledir.pc"
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix "${PWD}/tmp/child/pcfiledir.pc"
export PKG_CONFIG_PATH="."
atf_check \
-o inline:"tmp/child\n" \
pkgconf --variable=prefix pcfiledir
export PKG_CONFIG_PATH="${PWD}"
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix pcfiledir
export PKG_CONFIG_PATH="tmp"
atf_check \
-o inline:"tmp/child\n" \
pkgconf --variable=prefix pcfiledir
export PKG_CONFIG_PATH="${PWD}/tmp"
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix pcfiledir
export PKG_CONFIG_PATH="tmp/child"
atf_check \
-o inline:"tmp/child\n" \
pkgconf --variable=prefix pcfiledir
export PKG_CONFIG_PATH="${PWD}/tmp/child"
atf_check \
-o inline:"${PWD}/tmp/child\n" \
pkgconf --variable=prefix pcfiledir
}