From d1f48f11d5dffa1d954a1b0abe44ce9e4bfc3709 Mon Sep 17 00:00:00 2001 From: Tom Anderson Date: Wed, 11 Jul 2018 15:50:26 -0700 Subject: [PATCH] Return canonicalized paths from FcConfigRealFilename FcConfigRealFilename() follows symlinks, but the link may be relative to the directory containing the link. For example, on my system, I have this file: /etc/fonts/conf.d/99-language-selector-zh.conf -> ../conf.avail/99-language-selector-zh.conf Since /etc/fonts/conf.d is probably not in PATH, open()ing the file would fail. This change makes FcConfigRealFilename() return the canonicalized filename instead. So for the example above, it would return: /etc/fonts/conf.avail/99-language-selector-zh.conf This was causing bad font rendering in Chromium [1] after the regression I introduced in 7ad010e80bdf8e41303e322882ece908f5e04c74. [1] https://bugs.chromium.org/p/chromium/issues/detail?id=857511 --- src/fccfg.c | 65 ++++++++++++++++++++++++++++------------------------- src/fcint.h | 3 +++ src/fcstr.c | 11 +++++++++ 3 files changed, 49 insertions(+), 30 deletions(-) diff --git a/src/fccfg.c b/src/fccfg.c index 3d5c335..421b47c 100644 --- a/src/fccfg.c +++ b/src/fccfg.c @@ -2191,42 +2191,28 @@ FcConfigFilename (const FcChar8 *url) } file = 0; -#ifdef _WIN32 - if (isalpha (*url) && - url[1] == ':' && - (url[2] == '/' || url[2] == '\\')) - goto absolute_path; -#endif + if (FcStrIsAbsoluteFilename(url)) + return FcConfigFileExists (0, url); - switch (*url) { - case '~': + if (*url == '~') + { dir = FcConfigHome (); if (dir) file = FcConfigFileExists (dir, url + 1); else file = 0; - break; -#ifdef _WIN32 - case '\\': - absolute_path: -#endif - case '/': - file = FcConfigFileExists (0, url); - break; - default: - path = FcConfigGetPath (); - if (!path) - return NULL; - for (p = path; *p; p++) - { - file = FcConfigFileExists (*p, url); - if (file) - break; - } - FcConfigFreePath (path); - break; } + path = FcConfigGetPath (); + if (!path) + return NULL; + for (p = path; *p; p++) + { + file = FcConfigFileExists (*p, url); + if (file) + break; + } + FcConfigFreePath (path); return file; } @@ -2252,8 +2238,27 @@ FcConfigRealFilename (FcConfig *config, if ((len = FcReadLink (nn, buf, sizeof (buf) - 1)) != -1) { buf[len] = 0; - FcStrFree (nn); - nn = FcStrdup (buf); + + if (!FcStrIsAbsoluteFilename (buf)) + { + FcChar8 *dirname = FcStrDirname (nn); + FcStrFree (nn); + if (!dirname) + return NULL; + + FcChar8 *path = FcStrBuildFilename (dirname, buf, NULL); + FcStrFree (dirname); + if (!path) + return NULL; + + nn = FcStrCanonFilename (path); + FcStrFree (path); + } + else + { + FcStrFree (nn); + nn = FcStrdup (buf); + } } } diff --git a/src/fcint.h b/src/fcint.h index 598b76c..de78cd8 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -1279,6 +1279,9 @@ FcStrGlobMatch (const FcChar8 *glob, FcPrivate FcBool FcStrUsesHome (const FcChar8 *s); +FcPrivate FcBool +FcStrIsAbsoluteFilename (const FcChar8 *s); + FcPrivate FcChar8 * FcStrBuildFilename (const FcChar8 *path, ...); diff --git a/src/fcstr.c b/src/fcstr.c index b65492d..4d33ea5 100644 --- a/src/fcstr.c +++ b/src/fcstr.c @@ -867,6 +867,17 @@ FcStrUsesHome (const FcChar8 *s) return *s == '~'; } +FcBool +FcStrIsAbsoluteFilename (const FcChar8 *s) +{ +#ifdef _WIN32 + if (*s == '\\' || + (isalpha (*s) && s[1] == ':' && (s[2] == '/' || s[2] == '\\')) + return FcTrue; +#endif + return *s == '/'; +} + FcChar8 * FcStrBuildFilename (const FcChar8 *path, ...)