2002-02-15 00:34:13 +01:00
|
|
|
/*
|
2004-12-07 02:14:46 +01:00
|
|
|
* Copyright © 2000 Keith Packard
|
2005-09-03 06:56:56 +02:00
|
|
|
* Copyright © 2005 Patrick Lam
|
2002-02-15 00:34:13 +01:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
|
|
* the above copyright notice appear in all copies and that both that
|
|
|
|
* copyright notice and this permission notice appear in supporting
|
2010-11-10 22:45:42 +01:00
|
|
|
* documentation, and that the name of the author(s) not be used in
|
2002-02-15 00:34:13 +01:00
|
|
|
* advertising or publicity pertaining to distribution of the software without
|
2010-11-10 22:45:42 +01:00
|
|
|
* specific, written prior permission. The authors make no
|
2002-02-15 00:34:13 +01:00
|
|
|
* representations about the suitability of this software for any purpose. It
|
|
|
|
* is provided "as is" without express or implied warranty.
|
|
|
|
*
|
2009-03-12 21:00:08 +01:00
|
|
|
* THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
2002-02-15 00:34:13 +01:00
|
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
2009-03-12 21:00:08 +01:00
|
|
|
* EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
2002-02-15 00:34:13 +01:00
|
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
2006-04-25 07:57:41 +02:00
|
|
|
#include "fcint.h"
|
2010-12-28 07:59:19 +01:00
|
|
|
#include "fcarch.h"
|
2020-09-03 08:25:30 +02:00
|
|
|
#include "fcmd5.h"
|
2006-08-28 06:53:48 +02:00
|
|
|
#include <stdio.h>
|
2012-02-28 04:52:25 +01:00
|
|
|
#include <stdlib.h>
|
2005-07-25 06:10:09 +02:00
|
|
|
#include <fcntl.h>
|
2020-07-18 18:21:09 +02:00
|
|
|
#ifdef HAVE_DIRENT_H
|
2005-08-24 08:21:30 +02:00
|
|
|
#include <dirent.h>
|
2020-07-18 18:21:09 +02:00
|
|
|
#endif
|
2005-12-09 17:36:45 +01:00
|
|
|
#include <string.h>
|
2016-06-25 19:18:53 +02:00
|
|
|
#include <limits.h>
|
2005-08-31 01:03:42 +02:00
|
|
|
#include <sys/types.h>
|
2013-10-21 04:50:55 +02:00
|
|
|
#include <sys/stat.h>
|
2018-05-14 22:26:26 +02:00
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
#include <sys/time.h>
|
2020-06-25 19:38:48 +02:00
|
|
|
#else
|
|
|
|
#include <winsock2.h> /* for struct timeval */
|
2018-05-14 22:26:26 +02:00
|
|
|
#endif
|
|
|
|
|
2006-09-05 07:20:25 +02:00
|
|
|
#include <assert.h>
|
2006-04-07 06:42:32 +02:00
|
|
|
#if defined(HAVE_MMAP) || defined(__CYGWIN__)
|
2006-04-19 18:53:50 +02:00
|
|
|
# include <unistd.h>
|
2006-04-07 06:42:32 +02:00
|
|
|
# include <sys/mman.h>
|
|
|
|
#endif
|
2015-10-13 06:06:54 +02:00
|
|
|
#if defined(_WIN32)
|
|
|
|
#include <sys/locking.h>
|
2017-12-18 13:45:00 +01:00
|
|
|
#endif
|
2002-02-15 00:34:13 +01:00
|
|
|
|
2006-02-09 19:44:14 +01:00
|
|
|
#ifndef O_BINARY
|
|
|
|
#define O_BINARY 0
|
|
|
|
#endif
|
|
|
|
|
2017-09-06 10:01:19 +02:00
|
|
|
FcBool
|
2017-11-15 08:10:49 +01:00
|
|
|
FcDirCacheCreateUUID (FcChar8 *dir,
|
|
|
|
FcBool force,
|
|
|
|
FcConfig *config)
|
2017-09-06 10:01:19 +02:00
|
|
|
{
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
return FcTrue;
|
2017-09-06 10:01:19 +02:00
|
|
|
}
|
|
|
|
|
2018-06-11 10:03:17 +02:00
|
|
|
FcBool
|
|
|
|
FcDirCacheDeleteUUID (const FcChar8 *dir,
|
|
|
|
FcConfig *config)
|
|
|
|
{
|
2019-03-22 08:41:32 +01:00
|
|
|
FcBool ret = FcTrue;
|
|
|
|
#ifndef _WIN32
|
2019-11-01 06:43:42 +01:00
|
|
|
const FcChar8 *sysroot;
|
2018-09-28 11:08:52 +02:00
|
|
|
FcChar8 *target, *d;
|
|
|
|
struct stat statb;
|
|
|
|
struct timeval times[2];
|
2018-06-11 10:03:17 +02:00
|
|
|
|
2019-11-01 06:43:42 +01:00
|
|
|
config = FcConfigReference (config);
|
|
|
|
if (!config)
|
|
|
|
return FcFalse;
|
|
|
|
sysroot = FcConfigGetSysRoot (config);
|
2018-06-11 10:03:17 +02:00
|
|
|
if (sysroot)
|
2018-09-28 11:08:52 +02:00
|
|
|
d = FcStrBuildFilename (sysroot, dir, NULL);
|
2018-06-11 10:03:17 +02:00
|
|
|
else
|
2018-09-28 11:08:52 +02:00
|
|
|
d = FcStrBuildFilename (dir, NULL);
|
|
|
|
if (FcStat (d, &statb) != 0)
|
|
|
|
{
|
|
|
|
ret = FcFalse;
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
target = FcStrBuildFilename (d, ".uuid", NULL);
|
2018-06-11 10:03:17 +02:00
|
|
|
ret = unlink ((char *) target) == 0;
|
2018-10-01 09:01:26 +02:00
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
times[0].tv_sec = statb.st_atime;
|
|
|
|
times[1].tv_sec = statb.st_mtime;
|
2018-09-28 11:08:52 +02:00
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_MTIM
|
2018-10-01 09:01:26 +02:00
|
|
|
times[0].tv_usec = statb.st_atim.tv_nsec / 1000;
|
|
|
|
times[1].tv_usec = statb.st_mtim.tv_nsec / 1000;
|
2018-09-28 11:08:52 +02:00
|
|
|
#else
|
2018-10-01 09:01:26 +02:00
|
|
|
times[0].tv_usec = 0;
|
|
|
|
times[1].tv_usec = 0;
|
2018-09-28 11:08:52 +02:00
|
|
|
#endif
|
2018-10-01 09:01:26 +02:00
|
|
|
if (utimes ((const char *) d, times) != 0)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "Unable to revert mtime: %s\n", d);
|
|
|
|
}
|
2018-09-28 11:08:52 +02:00
|
|
|
}
|
|
|
|
FcStrFree (target);
|
|
|
|
bail:
|
|
|
|
FcStrFree (d);
|
2019-03-22 08:41:32 +01:00
|
|
|
#endif
|
2019-11-01 06:43:42 +01:00
|
|
|
FcConfigDestroy (config);
|
2018-06-11 10:03:17 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-09-06 10:01:19 +02:00
|
|
|
#define CACHEBASE_LEN (1 + 36 + 1 + sizeof (FC_ARCHITECTURE) + sizeof (FC_CACHE_SUFFIX))
|
2006-08-04 18:13:00 +02:00
|
|
|
|
2012-04-11 12:52:35 +02:00
|
|
|
static FcBool
|
|
|
|
FcCacheIsMmapSafe (int fd)
|
|
|
|
{
|
2012-10-07 23:42:18 +02:00
|
|
|
enum {
|
|
|
|
MMAP_NOT_INITIALIZED = 0,
|
|
|
|
MMAP_USE,
|
|
|
|
MMAP_DONT_USE,
|
|
|
|
MMAP_CHECK_FS,
|
|
|
|
} status;
|
|
|
|
static void *static_status;
|
2012-04-11 12:52:35 +02:00
|
|
|
|
2012-10-07 23:42:18 +02:00
|
|
|
status = (intptr_t) fc_atomic_ptr_get (&static_status);
|
2012-04-11 12:52:35 +02:00
|
|
|
|
2012-10-07 23:42:18 +02:00
|
|
|
if (status == MMAP_NOT_INITIALIZED)
|
|
|
|
{
|
|
|
|
const char *env = getenv ("FONTCONFIG_USE_MMAP");
|
|
|
|
FcBool use;
|
|
|
|
if (env && FcNameBool ((const FcChar8 *) env, &use))
|
|
|
|
status = use ? MMAP_USE : MMAP_DONT_USE;
|
|
|
|
else
|
|
|
|
status = MMAP_CHECK_FS;
|
2021-07-12 15:57:49 +02:00
|
|
|
(void) fc_atomic_ptr_cmpexch (&static_status, NULL, (void *) (intptr_t) status);
|
2012-04-11 12:52:35 +02:00
|
|
|
}
|
|
|
|
|
2012-10-07 23:42:18 +02:00
|
|
|
if (status == MMAP_CHECK_FS)
|
|
|
|
return FcIsFsMmapSafe (fd);
|
|
|
|
else
|
|
|
|
return status == MMAP_USE;
|
|
|
|
|
2012-04-11 12:52:35 +02:00
|
|
|
}
|
|
|
|
|
2006-08-04 18:13:00 +02:00
|
|
|
static const char bin2hex[] = { '0', '1', '2', '3',
|
|
|
|
'4', '5', '6', '7',
|
|
|
|
'8', '9', 'a', 'b',
|
|
|
|
'c', 'd', 'e', 'f' };
|
|
|
|
|
|
|
|
static FcChar8 *
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
FcDirCacheBasenameMD5 (FcConfig *config, const FcChar8 *dir, FcChar8 cache_base[CACHEBASE_LEN])
|
2005-10-05 02:34:52 +02:00
|
|
|
{
|
2019-04-04 13:57:13 +02:00
|
|
|
FcChar8 *mapped_dir = NULL;
|
2006-08-04 18:13:00 +02:00
|
|
|
unsigned char hash[16];
|
2019-01-31 11:17:47 +01:00
|
|
|
FcChar8 *hex_hash, *key = NULL;
|
2006-08-04 18:13:00 +02:00
|
|
|
int cnt;
|
|
|
|
struct MD5Context ctx;
|
2019-04-02 12:00:17 +02:00
|
|
|
const FcChar8 *salt, *orig_dir = NULL;
|
2005-10-05 02:34:52 +02:00
|
|
|
|
2019-01-31 11:17:47 +01:00
|
|
|
salt = FcConfigMapSalt (config, dir);
|
2019-04-04 13:57:13 +02:00
|
|
|
/* Obtain a path where "dir" is mapped to.
|
|
|
|
* In case:
|
|
|
|
* <remap-dir as-path="/usr/share/fonts">/run/host/fonts</remap-dir>
|
|
|
|
*
|
|
|
|
* FcConfigMapFontPath (config, "/run/host/fonts") will returns "/usr/share/fonts".
|
|
|
|
*/
|
|
|
|
mapped_dir = FcConfigMapFontPath(config, dir);
|
|
|
|
if (mapped_dir)
|
2019-04-02 12:00:17 +02:00
|
|
|
{
|
|
|
|
orig_dir = dir;
|
2019-04-04 13:57:13 +02:00
|
|
|
dir = mapped_dir;
|
2019-04-02 12:00:17 +02:00
|
|
|
}
|
2019-01-31 11:17:47 +01:00
|
|
|
if (salt)
|
|
|
|
{
|
|
|
|
size_t dl = strlen ((const char *) dir);
|
|
|
|
size_t sl = strlen ((const char *) salt);
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
|
2019-01-31 11:17:47 +01:00
|
|
|
key = (FcChar8 *) malloc (dl + sl + 1);
|
|
|
|
memcpy (key, dir, dl);
|
|
|
|
memcpy (key + dl, salt, sl + 1);
|
2019-04-02 12:25:46 +02:00
|
|
|
key[dl + sl] = 0;
|
2019-04-02 12:00:17 +02:00
|
|
|
if (!orig_dir)
|
|
|
|
orig_dir = dir;
|
2019-01-31 11:17:47 +01:00
|
|
|
dir = key;
|
|
|
|
}
|
2006-08-04 18:13:00 +02:00
|
|
|
MD5Init (&ctx);
|
2007-10-18 13:13:51 +02:00
|
|
|
MD5Update (&ctx, (const unsigned char *)dir, strlen ((const char *) dir));
|
2005-12-21 04:31:19 +01:00
|
|
|
|
2006-08-04 18:13:00 +02:00
|
|
|
MD5Final (hash, &ctx);
|
|
|
|
|
2019-01-31 11:17:47 +01:00
|
|
|
if (key)
|
|
|
|
FcStrFree (key);
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
|
2006-08-04 18:13:00 +02:00
|
|
|
cache_base[0] = '/';
|
|
|
|
hex_hash = cache_base + 1;
|
|
|
|
for (cnt = 0; cnt < 16; ++cnt)
|
2005-10-13 14:32:14 +02:00
|
|
|
{
|
2006-08-04 18:13:00 +02:00
|
|
|
hex_hash[2*cnt ] = bin2hex[hash[cnt] >> 4];
|
|
|
|
hex_hash[2*cnt+1] = bin2hex[hash[cnt] & 0xf];
|
|
|
|
}
|
|
|
|
hex_hash[2*cnt] = 0;
|
2006-08-28 03:29:51 +02:00
|
|
|
strcat ((char *) cache_base, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX);
|
2019-04-02 12:00:17 +02:00
|
|
|
if (FcDebug() & FC_DBG_CACHE)
|
|
|
|
{
|
2019-04-04 13:57:13 +02:00
|
|
|
printf ("cache: %s (dir: %s%s%s%s%s%s)\n", cache_base, orig_dir ? orig_dir : dir, mapped_dir ? " (mapped to " : "", mapped_dir ? (char *)mapped_dir : "", mapped_dir ? ")" : "", salt ? ", salt: " : "", salt ? (char *)salt : "");
|
2019-04-02 12:00:17 +02:00
|
|
|
}
|
|
|
|
|
2019-04-04 13:57:13 +02:00
|
|
|
if (mapped_dir)
|
|
|
|
FcStrFree(mapped_dir);
|
2006-01-25 03:33:46 +01:00
|
|
|
|
2006-08-04 18:13:00 +02:00
|
|
|
return cache_base;
|
|
|
|
}
|
2005-12-21 04:31:19 +01:00
|
|
|
|
2019-04-04 12:59:47 +02:00
|
|
|
#ifndef _WIN32
|
|
|
|
static FcChar8 *
|
|
|
|
FcDirCacheBasenameUUID (FcConfig *config, const FcChar8 *dir, FcChar8 cache_base[CACHEBASE_LEN])
|
|
|
|
{
|
|
|
|
FcChar8 *target, *fuuid;
|
|
|
|
const FcChar8 *sysroot = FcConfigGetSysRoot (config);
|
|
|
|
int fd;
|
|
|
|
|
2019-04-04 13:57:13 +02:00
|
|
|
/* We don't need to apply remapping here. because .uuid was created at that very directory
|
|
|
|
* to determine the cache name no matter where it was mapped to.
|
|
|
|
*/
|
2019-04-04 12:59:47 +02:00
|
|
|
cache_base[0] = 0;
|
|
|
|
if (sysroot)
|
|
|
|
target = FcStrBuildFilename (sysroot, dir, NULL);
|
|
|
|
else
|
|
|
|
target = FcStrdup (dir);
|
|
|
|
fuuid = FcStrBuildFilename (target, ".uuid", NULL);
|
|
|
|
if ((fd = FcOpen ((char *) fuuid, O_RDONLY)) != -1)
|
|
|
|
{
|
|
|
|
char suuid[37];
|
|
|
|
ssize_t len;
|
|
|
|
|
|
|
|
memset (suuid, 0, sizeof (suuid));
|
|
|
|
len = read (fd, suuid, 36);
|
|
|
|
suuid[36] = 0;
|
|
|
|
close (fd);
|
|
|
|
if (len < 0)
|
|
|
|
goto bail;
|
|
|
|
cache_base[0] = '/';
|
|
|
|
strcpy ((char *)&cache_base[1], suuid);
|
|
|
|
strcat ((char *) cache_base, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX);
|
|
|
|
if (FcDebug () & FC_DBG_CACHE)
|
|
|
|
{
|
2019-04-04 13:57:13 +02:00
|
|
|
printf ("cache fallbacks to: %s (dir: %s)\n", cache_base, dir);
|
2019-04-04 12:59:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
bail:
|
|
|
|
FcStrFree (fuuid);
|
|
|
|
FcStrFree (target);
|
|
|
|
|
|
|
|
return cache_base;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-08-04 18:13:00 +02:00
|
|
|
FcBool
|
|
|
|
FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config)
|
|
|
|
{
|
|
|
|
FcChar8 *cache_hashed = NULL;
|
|
|
|
FcChar8 cache_base[CACHEBASE_LEN];
|
2019-04-04 12:59:47 +02:00
|
|
|
#ifndef _WIN32
|
|
|
|
FcChar8 uuid_cache_base[CACHEBASE_LEN];
|
|
|
|
#endif
|
2006-08-04 18:13:00 +02:00
|
|
|
FcStrList *list;
|
|
|
|
FcChar8 *cache_dir;
|
2019-11-01 06:43:42 +01:00
|
|
|
const FcChar8 *sysroot;
|
|
|
|
FcBool ret = FcTrue;
|
|
|
|
|
|
|
|
config = FcConfigReference (config);
|
|
|
|
if (!config)
|
|
|
|
return FcFalse;
|
|
|
|
sysroot = FcConfigGetSysRoot (config);
|
2005-12-21 04:31:19 +01:00
|
|
|
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
FcDirCacheBasenameMD5 (config, dir, cache_base);
|
2019-04-04 12:59:47 +02:00
|
|
|
#ifndef _WIN32
|
|
|
|
FcDirCacheBasenameUUID (config, dir, uuid_cache_base);
|
|
|
|
#endif
|
2005-12-21 04:31:19 +01:00
|
|
|
|
2006-08-04 18:13:00 +02:00
|
|
|
list = FcStrListCreate (config->cacheDirs);
|
|
|
|
if (!list)
|
2019-11-01 06:43:42 +01:00
|
|
|
{
|
|
|
|
ret = FcFalse;
|
|
|
|
goto bail;
|
|
|
|
}
|
2006-08-04 18:13:00 +02:00
|
|
|
|
|
|
|
while ((cache_dir = FcStrListNext (list)))
|
2005-12-21 04:31:19 +01:00
|
|
|
{
|
2013-02-06 11:35:30 +01:00
|
|
|
if (sysroot)
|
|
|
|
cache_hashed = FcStrBuildFilename (sysroot, cache_dir, cache_base, NULL);
|
|
|
|
else
|
|
|
|
cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL);
|
2006-08-04 18:13:00 +02:00
|
|
|
if (!cache_hashed)
|
|
|
|
break;
|
2006-08-28 06:53:48 +02:00
|
|
|
(void) unlink ((char *) cache_hashed);
|
2007-08-05 21:31:03 +02:00
|
|
|
FcStrFree (cache_hashed);
|
2019-04-04 12:59:47 +02:00
|
|
|
#ifndef _WIN32
|
|
|
|
if (uuid_cache_base[0] != 0)
|
|
|
|
{
|
|
|
|
if (sysroot)
|
|
|
|
cache_hashed = FcStrBuildFilename (sysroot, cache_dir, uuid_cache_base, NULL);
|
|
|
|
else
|
|
|
|
cache_hashed = FcStrBuildFilename (cache_dir, uuid_cache_base, NULL);
|
|
|
|
if (!cache_hashed)
|
|
|
|
break;
|
|
|
|
(void) unlink ((char *) cache_hashed);
|
|
|
|
FcStrFree (cache_hashed);
|
|
|
|
}
|
|
|
|
#endif
|
2005-10-13 14:32:14 +02:00
|
|
|
}
|
2006-08-04 18:13:00 +02:00
|
|
|
FcStrListDone (list);
|
2019-04-04 12:59:47 +02:00
|
|
|
FcDirCacheDeleteUUID (dir, config);
|
2006-08-04 18:13:00 +02:00
|
|
|
/* return FcFalse if something went wrong */
|
|
|
|
if (cache_dir)
|
2019-11-01 06:43:42 +01:00
|
|
|
ret = FcFalse;
|
|
|
|
bail:
|
|
|
|
FcConfigDestroy (config);
|
|
|
|
|
|
|
|
return ret;
|
2005-08-25 09:38:02 +02:00
|
|
|
}
|
|
|
|
|
2005-08-24 08:21:30 +02:00
|
|
|
static int
|
2006-09-01 10:15:14 +02:00
|
|
|
FcDirCacheOpenFile (const FcChar8 *cache_file, struct stat *file_stat)
|
2005-08-24 08:21:30 +02:00
|
|
|
{
|
2006-09-01 10:15:14 +02:00
|
|
|
int fd;
|
2005-08-24 08:21:30 +02:00
|
|
|
|
2007-11-14 01:41:55 +01:00
|
|
|
#ifdef _WIN32
|
|
|
|
if (FcStat (cache_file, file_stat) < 0)
|
|
|
|
return -1;
|
|
|
|
#endif
|
2012-12-06 12:01:52 +01:00
|
|
|
fd = FcOpen((char *) cache_file, O_RDONLY | O_BINARY);
|
2006-09-01 10:15:14 +02:00
|
|
|
if (fd < 0)
|
|
|
|
return fd;
|
2007-11-14 01:41:55 +01:00
|
|
|
#ifndef _WIN32
|
2006-09-01 10:15:14 +02:00
|
|
|
if (fstat (fd, file_stat) < 0)
|
2005-08-24 08:21:30 +02:00
|
|
|
{
|
2006-09-01 10:15:14 +02:00
|
|
|
close (fd);
|
|
|
|
return -1;
|
2005-08-24 08:21:30 +02:00
|
|
|
}
|
2007-11-14 01:41:55 +01:00
|
|
|
#endif
|
2006-09-01 10:15:14 +02:00
|
|
|
return fd;
|
2005-08-24 08:21:30 +02:00
|
|
|
}
|
|
|
|
|
2010-04-12 18:18:50 +02:00
|
|
|
/*
|
2006-08-31 06:59:53 +02:00
|
|
|
* Look for a cache file for the specified dir. Attempt
|
|
|
|
* to use each one we find, stopping when the callback
|
|
|
|
* indicates success
|
2006-08-04 18:13:00 +02:00
|
|
|
*/
|
2006-08-31 06:59:53 +02:00
|
|
|
static FcBool
|
2010-04-12 18:18:50 +02:00
|
|
|
FcDirCacheProcess (FcConfig *config, const FcChar8 *dir,
|
2014-06-17 13:08:24 +02:00
|
|
|
FcBool (*callback) (FcConfig *config, int fd, struct stat *fd_stat,
|
2019-10-28 09:11:38 +01:00
|
|
|
struct stat *dir_stat, struct timeval *cache_mtime, void *closure),
|
2006-08-31 20:56:43 +02:00
|
|
|
void *closure, FcChar8 **cache_file_ret)
|
2005-12-09 17:36:45 +01:00
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
int fd = -1;
|
2006-08-04 18:13:00 +02:00
|
|
|
FcChar8 cache_base[CACHEBASE_LEN];
|
|
|
|
FcStrList *list;
|
2014-06-17 13:08:24 +02:00
|
|
|
FcChar8 *cache_dir, *d;
|
2006-08-28 02:04:01 +02:00
|
|
|
struct stat file_stat, dir_stat;
|
2006-08-31 06:59:53 +02:00
|
|
|
FcBool ret = FcFalse;
|
2014-06-17 13:08:24 +02:00
|
|
|
const FcChar8 *sysroot = FcConfigGetSysRoot (config);
|
2020-03-23 06:03:47 +01:00
|
|
|
struct timeval latest_mtime = (struct timeval){ 0 };
|
2006-08-28 02:04:01 +02:00
|
|
|
|
2014-06-17 13:08:24 +02:00
|
|
|
if (sysroot)
|
|
|
|
d = FcStrBuildFilename (sysroot, dir, NULL);
|
|
|
|
else
|
|
|
|
d = FcStrdup (dir);
|
|
|
|
if (FcStatChecksum (d, &dir_stat) < 0)
|
|
|
|
{
|
|
|
|
FcStrFree (d);
|
2006-08-31 06:59:53 +02:00
|
|
|
return FcFalse;
|
2014-06-17 13:08:24 +02:00
|
|
|
}
|
|
|
|
FcStrFree (d);
|
2006-01-10 14:15:05 +01:00
|
|
|
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
FcDirCacheBasenameMD5 (config, dir, cache_base);
|
2005-12-09 17:36:45 +01:00
|
|
|
|
2006-08-04 18:13:00 +02:00
|
|
|
list = FcStrListCreate (config->cacheDirs);
|
|
|
|
if (!list)
|
2006-08-31 06:59:53 +02:00
|
|
|
return FcFalse;
|
2006-08-04 18:13:00 +02:00
|
|
|
|
|
|
|
while ((cache_dir = FcStrListNext (list)))
|
2005-12-09 17:36:45 +01:00
|
|
|
{
|
2013-02-06 11:35:30 +01:00
|
|
|
FcChar8 *cache_hashed;
|
2019-04-04 12:59:47 +02:00
|
|
|
#ifndef _WIN32
|
|
|
|
FcBool retried = FcFalse;
|
|
|
|
#endif
|
2020-02-26 07:42:21 +01:00
|
|
|
|
2013-02-06 11:35:30 +01:00
|
|
|
if (sysroot)
|
|
|
|
cache_hashed = FcStrBuildFilename (sysroot, cache_dir, cache_base, NULL);
|
|
|
|
else
|
|
|
|
cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL);
|
2006-08-04 18:13:00 +02:00
|
|
|
if (!cache_hashed)
|
2006-02-11 06:01:32 +01:00
|
|
|
break;
|
2019-07-23 12:53:16 +02:00
|
|
|
#ifndef _WIN32
|
|
|
|
retry:
|
|
|
|
#endif
|
2006-09-01 10:15:14 +02:00
|
|
|
fd = FcDirCacheOpenFile (cache_hashed, &file_stat);
|
2006-08-30 13:16:22 +02:00
|
|
|
if (fd >= 0) {
|
2019-10-28 09:11:38 +01:00
|
|
|
ret = (*callback) (config, fd, &file_stat, &dir_stat, &latest_mtime, closure);
|
2007-10-18 13:13:51 +02:00
|
|
|
close (fd);
|
|
|
|
if (ret)
|
2006-08-28 02:04:01 +02:00
|
|
|
{
|
2007-10-18 13:13:51 +02:00
|
|
|
if (cache_file_ret)
|
2019-10-28 09:11:38 +01:00
|
|
|
{
|
|
|
|
if (*cache_file_ret)
|
|
|
|
FcStrFree (*cache_file_ret);
|
2007-10-18 13:13:51 +02:00
|
|
|
*cache_file_ret = cache_hashed;
|
2019-10-28 09:11:38 +01:00
|
|
|
}
|
2007-10-18 13:13:51 +02:00
|
|
|
else
|
|
|
|
FcStrFree (cache_hashed);
|
2006-08-28 02:04:01 +02:00
|
|
|
}
|
2019-10-31 08:15:25 +01:00
|
|
|
else
|
|
|
|
FcStrFree (cache_hashed);
|
2006-08-28 02:04:01 +02:00
|
|
|
}
|
2019-04-04 12:59:47 +02:00
|
|
|
#ifndef _WIN32
|
|
|
|
else if (!retried)
|
|
|
|
{
|
2019-07-23 12:53:16 +02:00
|
|
|
FcChar8 uuid_cache_base[CACHEBASE_LEN];
|
|
|
|
|
2019-04-04 12:59:47 +02:00
|
|
|
retried = FcTrue;
|
2019-07-23 12:53:16 +02:00
|
|
|
FcDirCacheBasenameUUID (config, dir, uuid_cache_base);
|
|
|
|
if (uuid_cache_base[0] != 0)
|
2019-04-04 12:59:47 +02:00
|
|
|
{
|
|
|
|
FcStrFree (cache_hashed);
|
2019-07-23 12:53:16 +02:00
|
|
|
if (sysroot)
|
|
|
|
cache_hashed = FcStrBuildFilename (sysroot, cache_dir, uuid_cache_base, NULL);
|
|
|
|
else
|
|
|
|
cache_hashed = FcStrBuildFilename (cache_dir, uuid_cache_base, NULL);
|
|
|
|
if (!cache_hashed)
|
|
|
|
break;
|
2019-04-04 12:59:47 +02:00
|
|
|
goto retry;
|
|
|
|
}
|
2019-10-31 08:15:25 +01:00
|
|
|
else
|
|
|
|
FcStrFree (cache_hashed);
|
2019-04-04 12:59:47 +02:00
|
|
|
}
|
|
|
|
#endif
|
2019-10-28 09:11:38 +01:00
|
|
|
else
|
|
|
|
FcStrFree (cache_hashed);
|
2006-08-04 18:13:00 +02:00
|
|
|
}
|
|
|
|
FcStrListDone (list);
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2020-03-23 06:03:47 +01:00
|
|
|
if (closure)
|
|
|
|
return !!(*((FcCache **)closure) != NULL);
|
2006-08-31 06:59:53 +02:00
|
|
|
return ret;
|
2005-12-09 17:36:45 +01:00
|
|
|
}
|
|
|
|
|
2006-09-05 07:20:25 +02:00
|
|
|
#define FC_CACHE_MIN_MMAP 1024
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip list element, make sure the 'next' pointer is the last thing
|
|
|
|
* in the structure, it will be allocated large enough to hold all
|
|
|
|
* of the necessary pointers
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct _FcCacheSkip FcCacheSkip;
|
|
|
|
|
|
|
|
struct _FcCacheSkip {
|
|
|
|
FcCache *cache;
|
2012-10-08 03:03:58 +02:00
|
|
|
FcRef ref;
|
2006-09-05 07:20:25 +02:00
|
|
|
intptr_t size;
|
2018-05-23 15:08:12 +02:00
|
|
|
void *allocated;
|
2006-09-05 07:20:25 +02:00
|
|
|
dev_t cache_dev;
|
|
|
|
ino_t cache_ino;
|
|
|
|
time_t cache_mtime;
|
2015-08-14 10:17:34 +02:00
|
|
|
long cache_mtime_nano;
|
2006-09-05 07:20:25 +02:00
|
|
|
FcCacheSkip *next[1];
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The head of the skip list; pointers for every possible level
|
|
|
|
* in the skip list, plus the largest level in the list
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define FC_CACHE_MAX_LEVEL 16
|
|
|
|
|
2012-10-10 21:24:31 +02:00
|
|
|
/* Protected by cache_lock below */
|
2006-09-05 07:20:25 +02:00
|
|
|
static FcCacheSkip *fcCacheChains[FC_CACHE_MAX_LEVEL];
|
|
|
|
static int fcCacheMaxLevel;
|
|
|
|
|
2012-02-28 04:52:25 +01:00
|
|
|
|
2012-10-09 02:02:05 +02:00
|
|
|
static FcMutex *cache_lock;
|
|
|
|
|
|
|
|
static void
|
|
|
|
lock_cache (void)
|
|
|
|
{
|
|
|
|
FcMutex *lock;
|
|
|
|
retry:
|
|
|
|
lock = fc_atomic_ptr_get (&cache_lock);
|
|
|
|
if (!lock) {
|
|
|
|
lock = (FcMutex *) malloc (sizeof (FcMutex));
|
|
|
|
FcMutexInit (lock);
|
|
|
|
if (!fc_atomic_ptr_cmpexch (&cache_lock, NULL, lock)) {
|
|
|
|
FcMutexFinish (lock);
|
|
|
|
goto retry;
|
|
|
|
}
|
2012-10-09 02:03:35 +02:00
|
|
|
|
|
|
|
FcMutexLock (lock);
|
|
|
|
/* Initialize random state */
|
|
|
|
FcRandom ();
|
|
|
|
return;
|
2012-10-09 02:02:05 +02:00
|
|
|
}
|
|
|
|
FcMutexLock (lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
unlock_cache (void)
|
|
|
|
{
|
2020-10-30 03:29:00 +01:00
|
|
|
FcMutex *lock;
|
|
|
|
lock = fc_atomic_ptr_get (&cache_lock);
|
|
|
|
FcMutexUnlock (lock);
|
2012-10-09 02:02:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_lock (void)
|
|
|
|
{
|
|
|
|
FcMutex *lock;
|
|
|
|
lock = fc_atomic_ptr_get (&cache_lock);
|
|
|
|
if (lock && fc_atomic_ptr_cmpexch (&cache_lock, lock, NULL)) {
|
|
|
|
FcMutexFinish (lock);
|
|
|
|
free (lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-09-05 07:20:25 +02:00
|
|
|
/*
|
|
|
|
* Generate a random level number, distributed
|
|
|
|
* so that each level is 1/4 as likely as the one before
|
|
|
|
*
|
|
|
|
* Note that level numbers run 1 <= level <= MAX_LEVEL
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
random_level (void)
|
|
|
|
{
|
|
|
|
/* tricky bit -- each bit is '1' 75% of the time */
|
2006-09-17 23:20:18 +02:00
|
|
|
long int bits = FcRandom () | FcRandom ();
|
2006-09-05 07:20:25 +02:00
|
|
|
int level = 0;
|
|
|
|
|
|
|
|
while (++level < FC_CACHE_MAX_LEVEL)
|
|
|
|
{
|
|
|
|
if (bits & 1)
|
|
|
|
break;
|
|
|
|
bits >>= 1;
|
|
|
|
}
|
|
|
|
return level;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Insert cache into the list
|
|
|
|
*/
|
|
|
|
static FcBool
|
|
|
|
FcCacheInsert (FcCache *cache, struct stat *cache_stat)
|
|
|
|
{
|
|
|
|
FcCacheSkip **update[FC_CACHE_MAX_LEVEL];
|
|
|
|
FcCacheSkip *s, **next;
|
|
|
|
int i, level;
|
|
|
|
|
2012-10-10 21:24:31 +02:00
|
|
|
lock_cache ();
|
|
|
|
|
2006-09-05 07:20:25 +02:00
|
|
|
/*
|
|
|
|
* Find links along each chain
|
|
|
|
*/
|
|
|
|
next = fcCacheChains;
|
|
|
|
for (i = fcCacheMaxLevel; --i >= 0; )
|
|
|
|
{
|
|
|
|
for (; (s = next[i]); next = s->next)
|
|
|
|
if (s->cache > cache)
|
|
|
|
break;
|
|
|
|
update[i] = &next[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create new list element
|
|
|
|
*/
|
|
|
|
level = random_level ();
|
|
|
|
if (level > fcCacheMaxLevel)
|
|
|
|
{
|
|
|
|
level = fcCacheMaxLevel + 1;
|
|
|
|
update[fcCacheMaxLevel] = &fcCacheChains[fcCacheMaxLevel];
|
|
|
|
fcCacheMaxLevel = level;
|
|
|
|
}
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-09-05 07:20:25 +02:00
|
|
|
s = malloc (sizeof (FcCacheSkip) + (level - 1) * sizeof (FcCacheSkip *));
|
|
|
|
if (!s)
|
|
|
|
return FcFalse;
|
|
|
|
|
|
|
|
s->cache = cache;
|
|
|
|
s->size = cache->size;
|
2018-05-23 15:08:12 +02:00
|
|
|
s->allocated = NULL;
|
2012-10-08 03:03:58 +02:00
|
|
|
FcRefInit (&s->ref, 1);
|
2006-09-10 01:41:58 +02:00
|
|
|
if (cache_stat)
|
|
|
|
{
|
|
|
|
s->cache_dev = cache_stat->st_dev;
|
|
|
|
s->cache_ino = cache_stat->st_ino;
|
|
|
|
s->cache_mtime = cache_stat->st_mtime;
|
2015-08-14 10:17:34 +02:00
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_MTIM
|
|
|
|
s->cache_mtime_nano = cache_stat->st_mtim.tv_nsec;
|
|
|
|
#else
|
|
|
|
s->cache_mtime_nano = 0;
|
|
|
|
#endif
|
2006-09-10 01:41:58 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
s->cache_dev = 0;
|
|
|
|
s->cache_ino = 0;
|
|
|
|
s->cache_mtime = 0;
|
2015-08-14 10:17:34 +02:00
|
|
|
s->cache_mtime_nano = 0;
|
2006-09-10 01:41:58 +02:00
|
|
|
}
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-09-05 07:20:25 +02:00
|
|
|
/*
|
|
|
|
* Insert into all fcCacheChains
|
|
|
|
*/
|
|
|
|
for (i = 0; i < level; i++)
|
|
|
|
{
|
|
|
|
s->next[i] = *update[i];
|
|
|
|
*update[i] = s;
|
|
|
|
}
|
2012-10-10 21:24:31 +02:00
|
|
|
|
|
|
|
unlock_cache ();
|
2006-09-05 07:20:25 +02:00
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
static FcCacheSkip *
|
2012-10-10 21:24:31 +02:00
|
|
|
FcCacheFindByAddrUnlocked (void *object)
|
2006-09-05 07:20:25 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
FcCacheSkip **next = fcCacheChains;
|
|
|
|
FcCacheSkip *s;
|
|
|
|
|
2013-01-16 14:30:44 +01:00
|
|
|
if (!object)
|
|
|
|
return NULL;
|
|
|
|
|
2006-09-05 07:20:25 +02:00
|
|
|
/*
|
|
|
|
* Walk chain pointers one level at a time
|
|
|
|
*/
|
|
|
|
for (i = fcCacheMaxLevel; --i >= 0;)
|
|
|
|
while (next[i] && (char *) object >= ((char *) next[i]->cache + next[i]->size))
|
|
|
|
next = next[i]->next;
|
|
|
|
/*
|
|
|
|
* Here we are
|
|
|
|
*/
|
|
|
|
s = next[0];
|
|
|
|
if (s && (char *) object < ((char *) s->cache + s->size))
|
|
|
|
return s;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-10-10 21:24:31 +02:00
|
|
|
static FcCacheSkip *
|
|
|
|
FcCacheFindByAddr (void *object)
|
|
|
|
{
|
|
|
|
FcCacheSkip *ret;
|
|
|
|
lock_cache ();
|
|
|
|
ret = FcCacheFindByAddrUnlocked (object);
|
|
|
|
unlock_cache ();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-09-05 07:20:25 +02:00
|
|
|
static void
|
2012-10-16 02:35:03 +02:00
|
|
|
FcCacheRemoveUnlocked (FcCache *cache)
|
2006-09-05 07:20:25 +02:00
|
|
|
{
|
|
|
|
FcCacheSkip **update[FC_CACHE_MAX_LEVEL];
|
|
|
|
FcCacheSkip *s, **next;
|
|
|
|
int i;
|
2018-05-23 15:08:12 +02:00
|
|
|
void *allocated;
|
2006-09-05 07:20:25 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Find links along each chain
|
|
|
|
*/
|
|
|
|
next = fcCacheChains;
|
|
|
|
for (i = fcCacheMaxLevel; --i >= 0; )
|
|
|
|
{
|
|
|
|
for (; (s = next[i]); next = s->next)
|
|
|
|
if (s->cache >= cache)
|
|
|
|
break;
|
|
|
|
update[i] = &next[i];
|
|
|
|
}
|
|
|
|
s = next[0];
|
|
|
|
for (i = 0; i < fcCacheMaxLevel && *update[i] == s; i++)
|
|
|
|
*update[i] = s->next[i];
|
|
|
|
while (fcCacheMaxLevel > 0 && fcCacheChains[fcCacheMaxLevel - 1] == NULL)
|
|
|
|
fcCacheMaxLevel--;
|
2018-05-23 15:08:12 +02:00
|
|
|
|
2018-11-30 11:42:26 +01:00
|
|
|
if (s)
|
2018-05-23 15:08:12 +02:00
|
|
|
{
|
2018-11-30 11:42:26 +01:00
|
|
|
allocated = s->allocated;
|
|
|
|
while (allocated)
|
|
|
|
{
|
|
|
|
/* First element in allocated chunk is the free list */
|
|
|
|
next = *(void **)allocated;
|
|
|
|
free (allocated);
|
|
|
|
allocated = next;
|
|
|
|
}
|
|
|
|
free (s);
|
2018-05-23 15:08:12 +02:00
|
|
|
}
|
2006-09-05 07:20:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static FcCache *
|
|
|
|
FcCacheFindByStat (struct stat *cache_stat)
|
|
|
|
{
|
|
|
|
FcCacheSkip *s;
|
|
|
|
|
2012-10-10 21:24:31 +02:00
|
|
|
lock_cache ();
|
2006-09-05 07:20:25 +02:00
|
|
|
for (s = fcCacheChains[0]; s; s = s->next[0])
|
|
|
|
if (s->cache_dev == cache_stat->st_dev &&
|
|
|
|
s->cache_ino == cache_stat->st_ino &&
|
|
|
|
s->cache_mtime == cache_stat->st_mtime)
|
2006-09-05 08:19:59 +02:00
|
|
|
{
|
2015-08-14 10:17:34 +02:00
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_MTIM
|
2018-07-09 19:07:12 +02:00
|
|
|
if (s->cache_mtime_nano != cache_stat->st_mtim.tv_nsec)
|
2015-08-14 10:17:34 +02:00
|
|
|
continue;
|
|
|
|
#endif
|
2012-10-08 03:03:58 +02:00
|
|
|
FcRefInc (&s->ref);
|
2012-10-10 21:24:31 +02:00
|
|
|
unlock_cache ();
|
2006-09-05 07:20:25 +02:00
|
|
|
return s->cache;
|
2006-09-05 08:19:59 +02:00
|
|
|
}
|
2012-10-10 21:24:31 +02:00
|
|
|
unlock_cache ();
|
2006-09-05 07:20:25 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-09-04 22:59:58 +02:00
|
|
|
static void
|
2012-10-16 02:35:03 +02:00
|
|
|
FcDirCacheDisposeUnlocked (FcCache *cache)
|
2006-09-04 22:59:58 +02:00
|
|
|
{
|
2012-10-16 02:35:03 +02:00
|
|
|
FcCacheRemoveUnlocked (cache);
|
|
|
|
|
2006-09-04 22:59:58 +02:00
|
|
|
switch (cache->magic) {
|
|
|
|
case FC_CACHE_MAGIC_ALLOC:
|
|
|
|
free (cache);
|
|
|
|
break;
|
|
|
|
case FC_CACHE_MAGIC_MMAP:
|
|
|
|
#if defined(HAVE_MMAP) || defined(__CYGWIN__)
|
|
|
|
munmap (cache, cache->size);
|
|
|
|
#elif defined(_WIN32)
|
|
|
|
UnmapViewOfFile (cache);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-09-05 07:20:25 +02:00
|
|
|
void
|
|
|
|
FcCacheObjectReference (void *object)
|
2006-09-04 22:59:58 +02:00
|
|
|
{
|
2006-09-05 07:20:25 +02:00
|
|
|
FcCacheSkip *skip = FcCacheFindByAddr (object);
|
2006-09-04 22:59:58 +02:00
|
|
|
|
2006-09-05 07:20:25 +02:00
|
|
|
if (skip)
|
2012-10-08 03:03:58 +02:00
|
|
|
FcRefInc (&skip->ref);
|
2006-09-04 22:59:58 +02:00
|
|
|
}
|
|
|
|
|
2006-09-05 07:20:25 +02:00
|
|
|
void
|
|
|
|
FcCacheObjectDereference (void *object)
|
2006-09-04 22:59:58 +02:00
|
|
|
{
|
2012-10-16 02:35:03 +02:00
|
|
|
FcCacheSkip *skip;
|
2006-09-04 22:59:58 +02:00
|
|
|
|
2012-10-16 02:35:03 +02:00
|
|
|
lock_cache ();
|
|
|
|
skip = FcCacheFindByAddrUnlocked (object);
|
2006-09-05 07:20:25 +02:00
|
|
|
if (skip)
|
|
|
|
{
|
2013-01-16 14:30:44 +01:00
|
|
|
if (FcRefDec (&skip->ref) == 1)
|
2012-10-16 02:35:03 +02:00
|
|
|
FcDirCacheDisposeUnlocked (skip->cache);
|
2006-09-05 07:20:25 +02:00
|
|
|
}
|
2012-10-16 02:35:03 +02:00
|
|
|
unlock_cache ();
|
2006-09-04 22:59:58 +02:00
|
|
|
}
|
|
|
|
|
2018-05-23 15:08:12 +02:00
|
|
|
void *
|
|
|
|
FcCacheAllocate (FcCache *cache, size_t len)
|
|
|
|
{
|
|
|
|
FcCacheSkip *skip;
|
|
|
|
void *allocated = NULL;
|
|
|
|
|
|
|
|
lock_cache ();
|
|
|
|
skip = FcCacheFindByAddrUnlocked (cache);
|
|
|
|
if (skip)
|
|
|
|
{
|
|
|
|
void *chunk = malloc (sizeof (void *) + len);
|
|
|
|
if (chunk)
|
|
|
|
{
|
|
|
|
/* First element in allocated chunk is the free list */
|
|
|
|
*(void **)chunk = skip->allocated;
|
|
|
|
skip->allocated = chunk;
|
|
|
|
/* Return the rest */
|
|
|
|
allocated = ((FcChar8 *)chunk) + sizeof (void *);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unlock_cache ();
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
2006-09-04 22:59:58 +02:00
|
|
|
void
|
|
|
|
FcCacheFini (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2006-09-05 07:20:25 +02:00
|
|
|
for (i = 0; i < FC_CACHE_MAX_LEVEL; i++)
|
2020-03-23 06:03:47 +01:00
|
|
|
{
|
|
|
|
if (FcDebug() & FC_DBG_CACHE)
|
|
|
|
{
|
|
|
|
if (fcCacheChains[i] != NULL)
|
|
|
|
{
|
|
|
|
FcCacheSkip *s = fcCacheChains[i];
|
2020-08-06 05:44:39 +02:00
|
|
|
printf("Fontconfig error: not freed %p (dir: %s, refcount %" FC_ATOMIC_INT_FORMAT ")\n", s->cache, FcCacheDir(s->cache), s->ref.count);
|
2020-03-23 06:03:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
assert (fcCacheChains[i] == NULL);
|
|
|
|
}
|
2006-09-05 07:20:25 +02:00
|
|
|
assert (fcCacheMaxLevel == 0);
|
2012-10-09 02:02:05 +02:00
|
|
|
|
|
|
|
free_lock ();
|
2006-09-04 22:59:58 +02:00
|
|
|
}
|
|
|
|
|
2007-10-18 13:13:51 +02:00
|
|
|
static FcBool
|
2014-06-17 13:08:24 +02:00
|
|
|
FcCacheTimeValid (FcConfig *config, FcCache *cache, struct stat *dir_stat)
|
2007-10-18 13:13:51 +02:00
|
|
|
{
|
|
|
|
struct stat dir_static;
|
2015-08-14 10:17:34 +02:00
|
|
|
FcBool fnano = FcTrue;
|
2007-10-18 13:13:51 +02:00
|
|
|
|
|
|
|
if (!dir_stat)
|
|
|
|
{
|
2014-06-17 13:08:24 +02:00
|
|
|
const FcChar8 *sysroot = FcConfigGetSysRoot (config);
|
|
|
|
FcChar8 *d;
|
|
|
|
|
|
|
|
if (sysroot)
|
|
|
|
d = FcStrBuildFilename (sysroot, FcCacheDir (cache), NULL);
|
|
|
|
else
|
|
|
|
d = FcStrdup (FcCacheDir (cache));
|
|
|
|
if (FcStatChecksum (d, &dir_static) < 0)
|
|
|
|
{
|
|
|
|
FcStrFree (d);
|
2007-10-18 13:13:51 +02:00
|
|
|
return FcFalse;
|
2014-06-17 13:08:24 +02:00
|
|
|
}
|
|
|
|
FcStrFree (d);
|
2007-10-18 13:13:51 +02:00
|
|
|
dir_stat = &dir_static;
|
|
|
|
}
|
2015-08-14 10:17:34 +02:00
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_MTIM
|
|
|
|
fnano = (cache->checksum_nano == dir_stat->st_mtim.tv_nsec);
|
|
|
|
if (FcDebug () & FC_DBG_CACHE)
|
2015-10-15 08:48:23 +02:00
|
|
|
printf ("FcCacheTimeValid dir \"%s\" cache checksum %d.%ld dir checksum %d.%ld\n",
|
|
|
|
FcCacheDir (cache), cache->checksum, (long)cache->checksum_nano, (int) dir_stat->st_mtime, dir_stat->st_mtim.tv_nsec);
|
2015-08-14 10:17:34 +02:00
|
|
|
#else
|
2007-10-18 13:13:51 +02:00
|
|
|
if (FcDebug () & FC_DBG_CACHE)
|
2012-05-28 07:52:21 +02:00
|
|
|
printf ("FcCacheTimeValid dir \"%s\" cache checksum %d dir checksum %d\n",
|
|
|
|
FcCacheDir (cache), cache->checksum, (int) dir_stat->st_mtime);
|
2015-08-14 10:17:34 +02:00
|
|
|
#endif
|
|
|
|
|
2020-05-12 14:03:28 +02:00
|
|
|
return dir_stat->st_mtime == 0 || (cache->checksum == (int) dir_stat->st_mtime && fnano);
|
2007-10-18 13:13:51 +02:00
|
|
|
}
|
|
|
|
|
2016-06-25 19:18:53 +02:00
|
|
|
static FcBool
|
|
|
|
FcCacheOffsetsValid (FcCache *cache)
|
|
|
|
{
|
|
|
|
char *base = (char *)cache;
|
|
|
|
char *end = base + cache->size;
|
|
|
|
intptr_t *dirs;
|
|
|
|
FcFontSet *fs;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
if (cache->dir < 0 || cache->dir > cache->size - sizeof (intptr_t) ||
|
|
|
|
memchr (base + cache->dir, '\0', cache->size - cache->dir) == NULL)
|
|
|
|
return FcFalse;
|
|
|
|
|
|
|
|
if (cache->dirs < 0 || cache->dirs >= cache->size ||
|
|
|
|
cache->dirs_count < 0 ||
|
|
|
|
cache->dirs_count > (cache->size - cache->dirs) / sizeof (intptr_t))
|
|
|
|
return FcFalse;
|
|
|
|
|
|
|
|
dirs = FcCacheDirs (cache);
|
|
|
|
if (dirs)
|
|
|
|
{
|
|
|
|
for (i = 0; i < cache->dirs_count; i++)
|
|
|
|
{
|
|
|
|
FcChar8 *dir;
|
|
|
|
|
|
|
|
if (dirs[i] < 0 ||
|
|
|
|
dirs[i] > end - (char *) dirs - sizeof (intptr_t))
|
|
|
|
return FcFalse;
|
|
|
|
|
|
|
|
dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
|
|
|
|
if (memchr (dir, '\0', end - (char *) dir) == NULL)
|
|
|
|
return FcFalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cache->set < 0 || cache->set > cache->size - sizeof (FcFontSet))
|
|
|
|
return FcFalse;
|
|
|
|
|
|
|
|
fs = FcCacheSet (cache);
|
|
|
|
if (fs)
|
|
|
|
{
|
|
|
|
if (fs->nfont > (end - (char *) fs) / sizeof (FcPattern))
|
|
|
|
return FcFalse;
|
|
|
|
|
2018-07-19 09:09:14 +02:00
|
|
|
if (!FcIsEncodedOffset(fs->fonts))
|
2016-06-25 19:18:53 +02:00
|
|
|
return FcFalse;
|
|
|
|
|
|
|
|
for (i = 0; i < fs->nfont; i++)
|
|
|
|
{
|
|
|
|
FcPattern *font = FcFontSetFont (fs, i);
|
|
|
|
FcPatternElt *e;
|
|
|
|
FcValueListPtr l;
|
2016-11-14 12:14:35 +01:00
|
|
|
char *last_offset;
|
2016-06-25 19:18:53 +02:00
|
|
|
|
|
|
|
if ((char *) font < base ||
|
|
|
|
(char *) font > end - sizeof (FcFontSet) ||
|
|
|
|
font->elts_offset < 0 ||
|
|
|
|
font->elts_offset > end - (char *) font ||
|
2017-11-14 12:55:24 +01:00
|
|
|
font->num > (end - (char *) font - font->elts_offset) / sizeof (FcPatternElt) ||
|
|
|
|
!FcRefIsConst (&font->ref))
|
2016-06-25 19:18:53 +02:00
|
|
|
return FcFalse;
|
|
|
|
|
|
|
|
|
|
|
|
e = FcPatternElts(font);
|
|
|
|
if (e->values != 0 && !FcIsEncodedOffset(e->values))
|
|
|
|
return FcFalse;
|
|
|
|
|
2016-11-14 12:14:35 +01:00
|
|
|
for (j = 0; j < font->num; j++)
|
|
|
|
{
|
|
|
|
last_offset = (char *) font + font->elts_offset;
|
|
|
|
for (l = FcPatternEltValues(&e[j]); l; l = FcValueListNext(l))
|
|
|
|
{
|
|
|
|
if ((char *) l < last_offset || (char *) l > end - sizeof (*l) ||
|
|
|
|
(l->next != NULL && !FcIsEncodedOffset(l->next)))
|
|
|
|
return FcFalse;
|
|
|
|
last_offset = (char *) l + 1;
|
|
|
|
}
|
|
|
|
}
|
2016-06-25 19:18:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
/*
|
|
|
|
* Map a cache file into memory
|
|
|
|
*/
|
|
|
|
static FcCache *
|
2014-06-17 13:08:24 +02:00
|
|
|
FcDirCacheMapFd (FcConfig *config, int fd, struct stat *fd_stat, struct stat *dir_stat)
|
2005-07-25 06:10:09 +02:00
|
|
|
{
|
2006-09-04 22:59:58 +02:00
|
|
|
FcCache *cache;
|
2006-08-30 13:16:22 +02:00
|
|
|
FcBool allocated = FcFalse;
|
2006-08-28 07:24:39 +02:00
|
|
|
|
2016-06-25 19:18:53 +02:00
|
|
|
if (fd_stat->st_size > INTPTR_MAX ||
|
|
|
|
fd_stat->st_size < (int) sizeof (FcCache))
|
2006-09-01 10:15:14 +02:00
|
|
|
return NULL;
|
2006-09-05 07:20:25 +02:00
|
|
|
cache = FcCacheFindByStat (fd_stat);
|
2006-09-04 22:59:58 +02:00
|
|
|
if (cache)
|
2009-02-04 03:06:15 +01:00
|
|
|
{
|
2016-04-06 07:39:15 +02:00
|
|
|
if (FcCacheTimeValid (config, cache, dir_stat))
|
2009-02-04 03:06:15 +01:00
|
|
|
return cache;
|
|
|
|
FcDirCacheUnload (cache);
|
|
|
|
cache = NULL;
|
|
|
|
}
|
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
/*
|
2012-04-11 12:52:35 +02:00
|
|
|
* Large cache files are mmap'ed, smaller cache files are read. This
|
2007-10-18 13:29:13 +02:00
|
|
|
* balances the system cost of mmap against per-process memory usage.
|
2006-09-01 10:15:14 +02:00
|
|
|
*/
|
2012-04-11 12:52:35 +02:00
|
|
|
if (FcCacheIsMmapSafe (fd) && fd_stat->st_size >= FC_CACHE_MIN_MMAP)
|
2006-09-01 10:15:14 +02:00
|
|
|
{
|
2006-04-07 06:42:32 +02:00
|
|
|
#if defined(HAVE_MMAP) || defined(__CYGWIN__)
|
2006-09-04 22:59:58 +02:00
|
|
|
cache = mmap (0, fd_stat->st_size, PROT_READ, MAP_SHARED, fd, 0);
|
2019-01-25 03:15:36 +01:00
|
|
|
#if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
|
2012-04-16 20:28:36 +02:00
|
|
|
posix_fadvise (fd, 0, fd_stat->st_size, POSIX_FADV_WILLNEED);
|
|
|
|
#endif
|
2009-04-06 01:00:18 +02:00
|
|
|
if (cache == MAP_FAILED)
|
|
|
|
cache = NULL;
|
2006-04-19 18:53:50 +02:00
|
|
|
#elif defined(_WIN32)
|
2006-08-30 13:16:22 +02:00
|
|
|
{
|
2006-09-01 10:15:14 +02:00
|
|
|
HANDLE hFileMap;
|
|
|
|
|
|
|
|
cache = NULL;
|
|
|
|
hFileMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL,
|
|
|
|
PAGE_READONLY, 0, 0, NULL);
|
|
|
|
if (hFileMap != NULL)
|
|
|
|
{
|
2010-04-12 18:18:50 +02:00
|
|
|
cache = MapViewOfFile (hFileMap, FILE_MAP_READ, 0, 0,
|
2006-09-18 02:03:33 +02:00
|
|
|
fd_stat->st_size);
|
2006-09-01 10:15:14 +02:00
|
|
|
CloseHandle (hFileMap);
|
|
|
|
}
|
2006-04-19 18:53:50 +02:00
|
|
|
}
|
2006-08-30 13:16:22 +02:00
|
|
|
#endif
|
2006-09-01 10:15:14 +02:00
|
|
|
}
|
2006-08-30 13:16:22 +02:00
|
|
|
if (!cache)
|
|
|
|
{
|
2006-09-04 22:59:58 +02:00
|
|
|
cache = malloc (fd_stat->st_size);
|
2006-08-30 13:16:22 +02:00
|
|
|
if (!cache)
|
2006-09-01 10:15:14 +02:00
|
|
|
return NULL;
|
2005-08-30 07:55:13 +02:00
|
|
|
|
2006-09-04 22:59:58 +02:00
|
|
|
if (read (fd, cache, fd_stat->st_size) != fd_stat->st_size)
|
2006-08-28 06:53:48 +02:00
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
free (cache);
|
2006-09-01 10:15:14 +02:00
|
|
|
return NULL;
|
2006-08-28 06:53:48 +02:00
|
|
|
}
|
2006-08-30 13:16:22 +02:00
|
|
|
allocated = FcTrue;
|
2010-04-12 18:18:50 +02:00
|
|
|
}
|
|
|
|
if (cache->magic != FC_CACHE_MAGIC_MMAP ||
|
2015-05-27 23:36:35 +02:00
|
|
|
cache->version < FC_CACHE_VERSION_NUMBER ||
|
2012-12-30 04:47:49 +01:00
|
|
|
cache->size != (intptr_t) fd_stat->st_size ||
|
2016-06-25 19:18:53 +02:00
|
|
|
!FcCacheOffsetsValid (cache) ||
|
2014-06-17 13:08:24 +02:00
|
|
|
!FcCacheTimeValid (config, cache, dir_stat) ||
|
2007-10-18 18:41:00 +02:00
|
|
|
!FcCacheInsert (cache, fd_stat))
|
2006-08-30 13:16:22 +02:00
|
|
|
{
|
|
|
|
if (allocated)
|
|
|
|
free (cache);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if defined(HAVE_MMAP) || defined(__CYGWIN__)
|
2006-09-04 22:59:58 +02:00
|
|
|
munmap (cache, fd_stat->st_size);
|
2006-08-30 13:16:22 +02:00
|
|
|
#elif defined(_WIN32)
|
|
|
|
UnmapViewOfFile (cache);
|
2006-08-28 06:53:48 +02:00
|
|
|
#endif
|
2006-08-30 13:16:22 +02:00
|
|
|
}
|
2006-09-01 10:15:14 +02:00
|
|
|
return NULL;
|
2006-08-28 06:53:48 +02:00
|
|
|
}
|
2006-08-28 07:24:39 +02:00
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
/* Mark allocated caches so they're freed rather than unmapped */
|
|
|
|
if (allocated)
|
2006-09-01 10:15:14 +02:00
|
|
|
cache->magic = FC_CACHE_MAGIC_ALLOC;
|
2006-08-30 13:16:22 +02:00
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
return cache;
|
|
|
|
}
|
|
|
|
|
2006-09-05 07:26:24 +02:00
|
|
|
void
|
|
|
|
FcDirCacheReference (FcCache *cache, int nref)
|
|
|
|
{
|
|
|
|
FcCacheSkip *skip = FcCacheFindByAddr (cache);
|
|
|
|
|
|
|
|
if (skip)
|
2012-10-08 03:03:58 +02:00
|
|
|
FcRefAdd (&skip->ref, nref);
|
2006-09-05 07:26:24 +02:00
|
|
|
}
|
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
void
|
|
|
|
FcDirCacheUnload (FcCache *cache)
|
|
|
|
{
|
2006-09-05 07:20:25 +02:00
|
|
|
FcCacheObjectDereference (cache);
|
2006-09-01 10:15:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static FcBool
|
2019-10-28 09:11:38 +01:00
|
|
|
FcDirCacheMapHelper (FcConfig *config, int fd, struct stat *fd_stat, struct stat *dir_stat, struct timeval *latest_cache_mtime, void *closure)
|
2006-09-01 10:15:14 +02:00
|
|
|
{
|
2014-06-17 13:08:24 +02:00
|
|
|
FcCache *cache = FcDirCacheMapFd (config, fd, fd_stat, dir_stat);
|
2020-05-12 14:03:28 +02:00
|
|
|
struct timeval cache_mtime, zero_mtime = { 0, 0}, dir_mtime;
|
2006-09-01 10:15:14 +02:00
|
|
|
|
|
|
|
if (!cache)
|
|
|
|
return FcFalse;
|
2019-10-28 09:11:38 +01:00
|
|
|
cache_mtime.tv_sec = fd_stat->st_mtime;
|
2020-05-12 14:03:28 +02:00
|
|
|
dir_mtime.tv_sec = dir_stat->st_mtime;
|
2019-10-28 09:11:38 +01:00
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_MTIM
|
|
|
|
cache_mtime.tv_usec = fd_stat->st_mtim.tv_nsec / 1000;
|
2020-05-12 14:03:28 +02:00
|
|
|
dir_mtime.tv_usec = dir_stat->st_mtim.tv_nsec / 1000;
|
2019-10-28 09:11:38 +01:00
|
|
|
#else
|
|
|
|
cache_mtime.tv_usec = 0;
|
2020-05-12 14:03:28 +02:00
|
|
|
dir_mtime.tv_usec = 0;
|
2019-10-28 09:11:38 +01:00
|
|
|
#endif
|
2020-05-12 14:03:28 +02:00
|
|
|
/* special take care of OSTree */
|
|
|
|
if (!timercmp (&zero_mtime, &dir_mtime, !=))
|
|
|
|
{
|
|
|
|
if (!timercmp (&zero_mtime, &cache_mtime, !=))
|
|
|
|
{
|
|
|
|
if (*((FcCache **) closure))
|
|
|
|
FcDirCacheUnload (*((FcCache **) closure));
|
|
|
|
}
|
|
|
|
else if (*((FcCache **) closure) && !timercmp (&zero_mtime, latest_cache_mtime, !=))
|
|
|
|
{
|
|
|
|
FcDirCacheUnload (cache);
|
|
|
|
return FcFalse;
|
|
|
|
}
|
|
|
|
else if (timercmp (latest_cache_mtime, &cache_mtime, <))
|
|
|
|
{
|
|
|
|
if (*((FcCache **) closure))
|
|
|
|
FcDirCacheUnload (*((FcCache **) closure));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (timercmp (latest_cache_mtime, &cache_mtime, <))
|
2019-10-28 09:11:38 +01:00
|
|
|
{
|
|
|
|
if (*((FcCache **) closure))
|
|
|
|
FcDirCacheUnload (*((FcCache **) closure));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FcDirCacheUnload (cache);
|
|
|
|
return FcFalse;
|
|
|
|
}
|
|
|
|
latest_cache_mtime->tv_sec = cache_mtime.tv_sec;
|
|
|
|
latest_cache_mtime->tv_usec = cache_mtime.tv_usec;
|
2006-08-31 06:59:53 +02:00
|
|
|
*((FcCache **) closure) = cache;
|
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
FcCache *
|
2006-09-01 10:15:14 +02:00
|
|
|
FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file)
|
2006-08-31 06:59:53 +02:00
|
|
|
{
|
2006-08-31 07:23:25 +02:00
|
|
|
FcCache *cache = NULL;
|
2006-08-31 06:59:53 +02:00
|
|
|
|
2019-11-01 06:43:42 +01:00
|
|
|
config = FcConfigReference (config);
|
|
|
|
if (!config)
|
|
|
|
return NULL;
|
2006-08-31 07:23:25 +02:00
|
|
|
if (!FcDirCacheProcess (config, dir,
|
2006-09-01 10:15:14 +02:00
|
|
|
FcDirCacheMapHelper,
|
2006-08-31 20:56:43 +02:00
|
|
|
&cache, cache_file))
|
2019-11-01 06:43:42 +01:00
|
|
|
cache = NULL;
|
|
|
|
|
|
|
|
FcConfigDestroy (config);
|
2017-08-02 12:02:19 +02:00
|
|
|
|
2006-08-31 07:23:25 +02:00
|
|
|
return cache;
|
2006-08-28 07:24:39 +02:00
|
|
|
}
|
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
FcCache *
|
|
|
|
FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat)
|
2006-08-28 07:24:39 +02:00
|
|
|
{
|
2006-09-01 10:15:14 +02:00
|
|
|
int fd;
|
2021-08-25 08:52:53 +02:00
|
|
|
FcCache *cache = NULL;
|
2007-11-03 22:16:29 +01:00
|
|
|
struct stat my_file_stat;
|
2019-11-01 06:43:42 +01:00
|
|
|
FcConfig *config;
|
2006-08-28 07:24:39 +02:00
|
|
|
|
2007-11-03 22:16:29 +01:00
|
|
|
if (!file_stat)
|
|
|
|
file_stat = &my_file_stat;
|
2019-11-01 06:43:42 +01:00
|
|
|
config = FcConfigReference (NULL);
|
2019-11-01 16:14:48 +01:00
|
|
|
if (!config)
|
|
|
|
return NULL;
|
2020-02-26 07:42:21 +01:00
|
|
|
fd = FcDirCacheOpenFile (cache_file, file_stat);
|
2021-08-25 08:52:53 +02:00
|
|
|
if (fd >= 0)
|
|
|
|
{
|
|
|
|
cache = FcDirCacheMapFd (config, fd, file_stat, NULL);
|
|
|
|
close (fd);
|
|
|
|
}
|
2019-11-01 06:43:42 +01:00
|
|
|
FcConfigDestroy (config);
|
2021-08-25 08:52:53 +02:00
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
return cache;
|
2005-08-30 07:55:13 +02:00
|
|
|
}
|
2006-09-01 10:15:14 +02:00
|
|
|
|
2018-05-15 22:11:24 +02:00
|
|
|
static int
|
|
|
|
FcDirChecksum (struct stat *statb)
|
|
|
|
{
|
|
|
|
int ret = (int) statb->st_mtime;
|
|
|
|
char *endptr;
|
|
|
|
char *source_date_epoch;
|
|
|
|
unsigned long long epoch;
|
|
|
|
|
|
|
|
source_date_epoch = getenv("SOURCE_DATE_EPOCH");
|
|
|
|
if (source_date_epoch)
|
|
|
|
{
|
2019-04-03 13:49:42 +02:00
|
|
|
errno = 0;
|
2018-05-15 22:11:24 +02:00
|
|
|
epoch = strtoull(source_date_epoch, &endptr, 10);
|
|
|
|
|
|
|
|
if (endptr == source_date_epoch)
|
|
|
|
fprintf (stderr,
|
|
|
|
"Fontconfig: SOURCE_DATE_EPOCH invalid\n");
|
|
|
|
else if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0))
|
|
|
|
|| (errno != 0 && epoch == 0))
|
|
|
|
fprintf (stderr,
|
2020-08-06 05:44:39 +02:00
|
|
|
"Fontconfig: SOURCE_DATE_EPOCH: strtoull: %s: %" FC_UINT64_FORMAT "\n",
|
2018-05-15 22:11:24 +02:00
|
|
|
strerror(errno), epoch);
|
|
|
|
else if (*endptr != '\0')
|
|
|
|
fprintf (stderr,
|
|
|
|
"Fontconfig: SOURCE_DATE_EPOCH has trailing garbage\n");
|
|
|
|
else if (epoch > ULONG_MAX)
|
|
|
|
fprintf (stderr,
|
2020-08-06 05:44:39 +02:00
|
|
|
"Fontconfig: SOURCE_DATE_EPOCH must be <= %lu but saw: %" FC_UINT64_FORMAT "\n",
|
2018-05-15 22:11:24 +02:00
|
|
|
ULONG_MAX, epoch);
|
|
|
|
else if (epoch < ret)
|
|
|
|
/* Only override if directory is newer */
|
|
|
|
ret = (int) epoch;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int64_t
|
|
|
|
FcDirChecksumNano (struct stat *statb)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_MTIM
|
|
|
|
/* No nanosecond component to parse */
|
|
|
|
if (getenv("SOURCE_DATE_EPOCH"))
|
|
|
|
return 0;
|
|
|
|
return statb->st_mtim.tv_nsec;
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
/*
|
|
|
|
* Validate a cache file by reading the header and checking
|
|
|
|
* the magic number and the size field
|
|
|
|
*/
|
2006-08-31 06:59:53 +02:00
|
|
|
static FcBool
|
2019-10-28 09:11:38 +01:00
|
|
|
FcDirCacheValidateHelper (FcConfig *config, int fd, struct stat *fd_stat, struct stat *dir_stat, struct timeval *latest_cache_mtime, void *closure FC_UNUSED)
|
2006-08-31 06:59:53 +02:00
|
|
|
{
|
|
|
|
FcBool ret = FcTrue;
|
|
|
|
FcCache c;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-08-31 06:59:53 +02:00
|
|
|
if (read (fd, &c, sizeof (FcCache)) != sizeof (FcCache))
|
|
|
|
ret = FcFalse;
|
2006-09-01 10:15:14 +02:00
|
|
|
else if (c.magic != FC_CACHE_MAGIC_MMAP)
|
|
|
|
ret = FcFalse;
|
2015-05-27 23:36:35 +02:00
|
|
|
else if (c.version < FC_CACHE_VERSION_NUMBER)
|
2006-08-31 06:59:53 +02:00
|
|
|
ret = FcFalse;
|
2006-09-04 22:59:58 +02:00
|
|
|
else if (fd_stat->st_size != c.size)
|
2006-08-31 06:59:53 +02:00
|
|
|
ret = FcFalse;
|
2018-05-15 22:11:24 +02:00
|
|
|
else if (c.checksum != FcDirChecksum (dir_stat))
|
2007-10-18 13:13:51 +02:00
|
|
|
ret = FcFalse;
|
2015-08-14 10:17:34 +02:00
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_MTIM
|
2018-05-15 22:11:24 +02:00
|
|
|
else if (c.checksum_nano != FcDirChecksumNano (dir_stat))
|
2015-08-14 10:17:34 +02:00
|
|
|
ret = FcFalse;
|
|
|
|
#endif
|
2006-08-31 06:59:53 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-08-31 23:38:18 +02:00
|
|
|
static FcBool
|
|
|
|
FcDirCacheValidConfig (const FcChar8 *dir, FcConfig *config)
|
2006-08-31 06:59:53 +02:00
|
|
|
{
|
2010-04-12 18:18:50 +02:00
|
|
|
return FcDirCacheProcess (config, dir,
|
2006-09-01 10:15:14 +02:00
|
|
|
FcDirCacheValidateHelper,
|
|
|
|
NULL, NULL);
|
2006-08-31 06:59:53 +02:00
|
|
|
}
|
|
|
|
|
2006-08-31 23:38:18 +02:00
|
|
|
FcBool
|
|
|
|
FcDirCacheValid (const FcChar8 *dir)
|
|
|
|
{
|
|
|
|
FcConfig *config;
|
2019-11-01 06:43:42 +01:00
|
|
|
FcBool ret;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2019-11-01 06:43:42 +01:00
|
|
|
config = FcConfigReference (NULL);
|
2006-08-31 23:38:18 +02:00
|
|
|
if (!config)
|
|
|
|
return FcFalse;
|
|
|
|
|
2019-11-01 06:43:42 +01:00
|
|
|
ret = FcDirCacheValidConfig (dir, config);
|
|
|
|
FcConfigDestroy (config);
|
|
|
|
|
|
|
|
return ret;
|
2006-08-31 23:38:18 +02:00
|
|
|
}
|
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
/*
|
2006-09-01 10:15:14 +02:00
|
|
|
* Build a cache structure from the given contents
|
2006-08-30 13:16:22 +02:00
|
|
|
*/
|
2006-09-01 10:15:14 +02:00
|
|
|
FcCache *
|
2007-10-18 13:13:51 +02:00
|
|
|
FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcStrSet *dirs)
|
2005-08-30 07:55:13 +02:00
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
FcSerialize *serialize = FcSerializeCreate ();
|
|
|
|
FcCache *cache;
|
|
|
|
int i;
|
|
|
|
FcChar8 *dir_serialize;
|
|
|
|
intptr_t *dirs_serialize;
|
|
|
|
FcFontSet *set_serialize;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
if (!serialize)
|
|
|
|
return NULL;
|
|
|
|
/*
|
|
|
|
* Space for cache structure
|
|
|
|
*/
|
2011-11-07 21:18:26 +01:00
|
|
|
FcSerializeReserve (serialize, sizeof (FcCache));
|
2006-08-30 13:16:22 +02:00
|
|
|
/*
|
|
|
|
* Directory name
|
|
|
|
*/
|
|
|
|
if (!FcStrSerializeAlloc (serialize, dir))
|
|
|
|
goto bail1;
|
|
|
|
/*
|
|
|
|
* Subdirs
|
|
|
|
*/
|
2011-11-07 21:18:26 +01:00
|
|
|
FcSerializeAlloc (serialize, dirs, dirs->num * sizeof (FcChar8 *));
|
2006-08-30 13:16:22 +02:00
|
|
|
for (i = 0; i < dirs->num; i++)
|
|
|
|
if (!FcStrSerializeAlloc (serialize, dirs->strs[i]))
|
|
|
|
goto bail1;
|
2005-08-30 07:55:13 +02:00
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
/*
|
|
|
|
* Patterns
|
|
|
|
*/
|
|
|
|
if (!FcFontSetSerializeAlloc (serialize, set))
|
|
|
|
goto bail1;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
/* Serialize layout complete. Now allocate space and fill it */
|
|
|
|
cache = malloc (serialize->size);
|
|
|
|
if (!cache)
|
|
|
|
goto bail1;
|
|
|
|
/* shut up valgrind */
|
|
|
|
memset (cache, 0, serialize->size);
|
2006-04-07 06:42:32 +02:00
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
serialize->linear = cache;
|
2005-08-30 07:55:13 +02:00
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
cache->magic = FC_CACHE_MAGIC_ALLOC;
|
2015-05-27 23:36:35 +02:00
|
|
|
cache->version = FC_CACHE_VERSION_NUMBER;
|
2006-08-30 13:16:22 +02:00
|
|
|
cache->size = serialize->size;
|
2018-05-15 22:11:24 +02:00
|
|
|
cache->checksum = FcDirChecksum (dir_stat);
|
|
|
|
cache->checksum_nano = FcDirChecksumNano (dir_stat);
|
2005-08-30 07:55:13 +02:00
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
/*
|
|
|
|
* Serialize directory name
|
|
|
|
*/
|
|
|
|
dir_serialize = FcStrSerialize (serialize, dir);
|
|
|
|
if (!dir_serialize)
|
|
|
|
goto bail2;
|
|
|
|
cache->dir = FcPtrToOffset (cache, dir_serialize);
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
/*
|
|
|
|
* Serialize sub dirs
|
|
|
|
*/
|
|
|
|
dirs_serialize = FcSerializePtr (serialize, dirs);
|
|
|
|
if (!dirs_serialize)
|
|
|
|
goto bail2;
|
|
|
|
cache->dirs = FcPtrToOffset (cache, dirs_serialize);
|
|
|
|
cache->dirs_count = dirs->num;
|
2010-04-12 18:18:50 +02:00
|
|
|
for (i = 0; i < dirs->num; i++)
|
2005-11-16 18:49:01 +01:00
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
FcChar8 *d_serialize = FcStrSerialize (serialize, dirs->strs[i]);
|
|
|
|
if (!d_serialize)
|
|
|
|
goto bail2;
|
|
|
|
dirs_serialize[i] = FcPtrToOffset (dirs_serialize, d_serialize);
|
2005-11-16 18:49:01 +01:00
|
|
|
}
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
/*
|
|
|
|
* Serialize font set
|
|
|
|
*/
|
|
|
|
set_serialize = FcFontSetSerialize (serialize, set);
|
|
|
|
if (!set_serialize)
|
|
|
|
goto bail2;
|
|
|
|
cache->set = FcPtrToOffset (cache, set_serialize);
|
2005-08-30 07:55:13 +02:00
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
FcSerializeDestroy (serialize);
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-09-10 01:41:58 +02:00
|
|
|
FcCacheInsert (cache, NULL);
|
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
return cache;
|
2005-07-25 06:10:09 +02:00
|
|
|
|
2006-08-30 13:16:22 +02:00
|
|
|
bail2:
|
|
|
|
free (cache);
|
|
|
|
bail1:
|
|
|
|
FcSerializeDestroy (serialize);
|
|
|
|
return NULL;
|
2005-07-25 06:10:09 +02:00
|
|
|
}
|
|
|
|
|
2013-12-05 11:15:47 +01:00
|
|
|
FcCache *
|
|
|
|
FcDirCacheRebuild (FcCache *cache, struct stat *dir_stat, FcStrSet *dirs)
|
|
|
|
{
|
|
|
|
FcCache *new;
|
|
|
|
FcFontSet *set = FcFontSetDeserialize (FcCacheSet (cache));
|
|
|
|
const FcChar8 *dir = FcCacheDir (cache);
|
|
|
|
|
|
|
|
new = FcDirCacheBuild (set, dir, dir_stat, dirs);
|
|
|
|
FcFontSetDestroy (set);
|
|
|
|
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
2005-07-25 06:10:09 +02:00
|
|
|
/* write serialized state to the cache file */
|
|
|
|
FcBool
|
2006-09-01 10:15:14 +02:00
|
|
|
FcDirCacheWrite (FcCache *cache, FcConfig *config)
|
2005-07-25 06:10:09 +02:00
|
|
|
{
|
2006-09-01 10:15:14 +02:00
|
|
|
FcChar8 *dir = FcCacheDir (cache);
|
2006-08-04 18:13:00 +02:00
|
|
|
FcChar8 cache_base[CACHEBASE_LEN];
|
|
|
|
FcChar8 *cache_hashed;
|
2006-08-30 13:16:22 +02:00
|
|
|
int fd;
|
2005-09-28 02:23:15 +02:00
|
|
|
FcAtomic *atomic;
|
2006-08-28 06:53:48 +02:00
|
|
|
FcStrList *list;
|
2006-08-28 02:04:01 +02:00
|
|
|
FcChar8 *cache_dir = NULL;
|
2013-02-06 11:35:30 +01:00
|
|
|
FcChar8 *test_dir, *d = NULL;
|
2009-02-05 08:46:16 +01:00
|
|
|
FcCacheSkip *skip;
|
|
|
|
struct stat cache_stat;
|
2012-12-30 04:47:49 +01:00
|
|
|
unsigned int magic;
|
2006-09-01 10:15:14 +02:00
|
|
|
int written;
|
2013-02-06 11:35:30 +01:00
|
|
|
const FcChar8 *sysroot = FcConfigGetSysRoot (config);
|
2005-07-25 06:10:09 +02:00
|
|
|
|
2006-08-04 18:13:00 +02:00
|
|
|
/*
|
2006-08-28 02:04:01 +02:00
|
|
|
* Write it to the first directory in the list which is writable
|
2006-08-04 18:13:00 +02:00
|
|
|
*/
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-08-28 02:04:01 +02:00
|
|
|
list = FcStrListCreate (config->cacheDirs);
|
|
|
|
if (!list)
|
|
|
|
return FcFalse;
|
2013-02-06 11:35:30 +01:00
|
|
|
while ((test_dir = FcStrListNext (list)))
|
|
|
|
{
|
|
|
|
if (d)
|
|
|
|
FcStrFree (d);
|
|
|
|
if (sysroot)
|
|
|
|
d = FcStrBuildFilename (sysroot, test_dir, NULL);
|
|
|
|
else
|
|
|
|
d = FcStrCopyFilename (test_dir);
|
|
|
|
|
|
|
|
if (access ((char *) d, W_OK) == 0)
|
2006-08-28 02:04:01 +02:00
|
|
|
{
|
2013-02-06 11:35:30 +01:00
|
|
|
cache_dir = FcStrCopyFilename (d);
|
2006-08-28 02:04:01 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-08-04 18:13:00 +02:00
|
|
|
/*
|
|
|
|
* If the directory doesn't exist, try to create it
|
|
|
|
*/
|
2013-02-06 11:35:30 +01:00
|
|
|
if (access ((char *) d, F_OK) == -1) {
|
|
|
|
if (FcMakeDirectory (d))
|
2006-08-28 02:04:01 +02:00
|
|
|
{
|
2013-02-06 11:35:30 +01:00
|
|
|
cache_dir = FcStrCopyFilename (d);
|
2012-03-28 10:28:06 +02:00
|
|
|
/* Create CACHEDIR.TAG */
|
2013-02-06 11:35:30 +01:00
|
|
|
FcDirCacheCreateTagFile (d);
|
2006-08-04 18:13:00 +02:00
|
|
|
break;
|
2006-08-28 02:04:01 +02:00
|
|
|
}
|
2006-08-04 18:13:00 +02:00
|
|
|
}
|
2008-12-28 22:54:44 +01:00
|
|
|
/*
|
|
|
|
* Otherwise, try making it writable
|
|
|
|
*/
|
2013-02-06 11:35:30 +01:00
|
|
|
else if (chmod ((char *) d, 0755) == 0)
|
2008-12-28 22:54:44 +01:00
|
|
|
{
|
2013-02-06 11:35:30 +01:00
|
|
|
cache_dir = FcStrCopyFilename (d);
|
2012-03-28 10:28:06 +02:00
|
|
|
/* Try to create CACHEDIR.TAG too */
|
2013-02-06 11:35:30 +01:00
|
|
|
FcDirCacheCreateTagFile (d);
|
2008-12-28 22:54:44 +01:00
|
|
|
break;
|
|
|
|
}
|
2006-08-04 18:13:00 +02:00
|
|
|
}
|
|
|
|
}
|
2020-07-14 12:24:36 +02:00
|
|
|
if (!test_dir)
|
|
|
|
fprintf (stderr, "Fontconfig error: No writable cache directories\n");
|
2013-02-06 11:35:30 +01:00
|
|
|
if (d)
|
|
|
|
FcStrFree (d);
|
2006-08-28 02:04:01 +02:00
|
|
|
FcStrListDone (list);
|
|
|
|
if (!cache_dir)
|
|
|
|
return FcFalse;
|
2006-08-30 13:16:22 +02:00
|
|
|
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
FcDirCacheBasenameMD5 (config, dir, cache_base);
|
2013-02-06 11:35:30 +01:00
|
|
|
cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL);
|
2018-07-19 04:40:31 +02:00
|
|
|
FcStrFree (cache_dir);
|
2006-08-28 02:04:01 +02:00
|
|
|
if (!cache_hashed)
|
|
|
|
return FcFalse;
|
2005-12-09 17:36:45 +01:00
|
|
|
|
2005-08-24 08:21:30 +02:00
|
|
|
if (FcDebug () & FC_DBG_CACHE)
|
2006-04-27 09:11:44 +02:00
|
|
|
printf ("FcDirCacheWriteDir dir \"%s\" file \"%s\"\n",
|
|
|
|
dir, cache_hashed);
|
2005-08-24 08:21:30 +02:00
|
|
|
|
2005-12-21 04:31:19 +01:00
|
|
|
atomic = FcAtomicCreate ((FcChar8 *)cache_hashed);
|
2005-09-28 02:23:15 +02:00
|
|
|
if (!atomic)
|
2006-09-01 10:15:14 +02:00
|
|
|
goto bail1;
|
2005-07-25 06:10:09 +02:00
|
|
|
|
2005-09-28 02:23:15 +02:00
|
|
|
if (!FcAtomicLock (atomic))
|
2006-08-30 13:16:22 +02:00
|
|
|
goto bail3;
|
2005-12-12 21:45:54 +01:00
|
|
|
|
2012-12-06 12:01:52 +01:00
|
|
|
fd = FcOpen((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT | O_BINARY, 0666);
|
2005-09-28 02:23:15 +02:00
|
|
|
if (fd == -1)
|
2006-08-30 13:16:22 +02:00
|
|
|
goto bail4;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
/* Temporarily switch magic to MMAP while writing to file */
|
|
|
|
magic = cache->magic;
|
|
|
|
if (magic != FC_CACHE_MAGIC_MMAP)
|
|
|
|
cache->magic = FC_CACHE_MAGIC_MMAP;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
/*
|
|
|
|
* Write cache contents to file
|
|
|
|
*/
|
|
|
|
written = write (fd, cache, cache->size);
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
/* Switch magic back */
|
|
|
|
if (magic != FC_CACHE_MAGIC_MMAP)
|
|
|
|
cache->magic = magic;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
if (written != cache->size)
|
2006-02-06 23:44:02 +01:00
|
|
|
{
|
2006-08-30 13:16:22 +02:00
|
|
|
perror ("write cache");
|
2006-02-05 03:57:21 +01:00
|
|
|
goto bail5;
|
|
|
|
}
|
2005-08-24 08:21:30 +02:00
|
|
|
|
2005-07-25 06:10:09 +02:00
|
|
|
close(fd);
|
2005-09-28 02:23:15 +02:00
|
|
|
if (!FcAtomicReplaceOrig(atomic))
|
2006-08-30 13:16:22 +02:00
|
|
|
goto bail4;
|
2009-02-05 08:46:16 +01:00
|
|
|
|
|
|
|
/* If the file is small, update the cache chain entry such that the
|
|
|
|
* new cache file is not read again. If it's large, we don't do that
|
|
|
|
* such that we reload it, using mmap, which is shared across processes.
|
|
|
|
*/
|
2012-10-10 21:24:31 +02:00
|
|
|
if (cache->size < FC_CACHE_MIN_MMAP && FcStat (cache_hashed, &cache_stat))
|
2009-02-05 08:46:16 +01:00
|
|
|
{
|
2012-10-10 21:24:31 +02:00
|
|
|
lock_cache ();
|
|
|
|
if ((skip = FcCacheFindByAddrUnlocked (cache)))
|
|
|
|
{
|
|
|
|
skip->cache_dev = cache_stat.st_dev;
|
|
|
|
skip->cache_ino = cache_stat.st_ino;
|
|
|
|
skip->cache_mtime = cache_stat.st_mtime;
|
2015-08-14 10:17:34 +02:00
|
|
|
#ifdef HAVE_STRUCT_STAT_ST_MTIM
|
|
|
|
skip->cache_mtime_nano = cache_stat.st_mtim.tv_nsec;
|
|
|
|
#else
|
|
|
|
skip->cache_mtime_nano = 0;
|
|
|
|
#endif
|
2012-10-10 21:24:31 +02:00
|
|
|
}
|
|
|
|
unlock_cache ();
|
2009-02-05 08:46:16 +01:00
|
|
|
}
|
|
|
|
|
2006-09-01 10:15:14 +02:00
|
|
|
FcStrFree (cache_hashed);
|
2005-09-28 02:23:15 +02:00
|
|
|
FcAtomicUnlock (atomic);
|
|
|
|
FcAtomicDestroy (atomic);
|
2005-07-25 06:10:09 +02:00
|
|
|
return FcTrue;
|
|
|
|
|
2005-12-09 17:36:45 +01:00
|
|
|
bail5:
|
2005-09-28 02:23:15 +02:00
|
|
|
close (fd);
|
2006-08-30 13:16:22 +02:00
|
|
|
bail4:
|
2005-09-28 02:23:15 +02:00
|
|
|
FcAtomicUnlock (atomic);
|
2006-08-30 13:16:22 +02:00
|
|
|
bail3:
|
2005-09-28 02:23:15 +02:00
|
|
|
FcAtomicDestroy (atomic);
|
2005-12-09 17:36:45 +01:00
|
|
|
bail1:
|
2006-09-01 10:15:14 +02:00
|
|
|
FcStrFree (cache_hashed);
|
2005-08-24 08:21:30 +02:00
|
|
|
return FcFalse;
|
|
|
|
}
|
|
|
|
|
2012-04-18 05:55:23 +02:00
|
|
|
FcBool
|
|
|
|
FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose)
|
|
|
|
{
|
|
|
|
DIR *d;
|
|
|
|
struct dirent *ent;
|
2013-02-06 11:35:30 +01:00
|
|
|
FcChar8 *dir;
|
2012-04-18 05:55:23 +02:00
|
|
|
FcBool ret = FcTrue;
|
|
|
|
FcBool remove;
|
|
|
|
FcCache *cache;
|
|
|
|
struct stat target_stat;
|
2013-02-06 11:35:30 +01:00
|
|
|
const FcChar8 *sysroot;
|
2019-11-01 06:43:42 +01:00
|
|
|
FcConfig *config;
|
2012-04-18 05:55:23 +02:00
|
|
|
|
2019-11-01 06:43:42 +01:00
|
|
|
config = FcConfigReference (NULL);
|
|
|
|
if (!config)
|
|
|
|
return FcFalse;
|
2013-02-06 11:35:30 +01:00
|
|
|
/* FIXME: this API needs to support non-current FcConfig */
|
2019-11-01 06:43:42 +01:00
|
|
|
sysroot = FcConfigGetSysRoot (config);
|
2013-02-06 11:35:30 +01:00
|
|
|
if (sysroot)
|
|
|
|
dir = FcStrBuildFilename (sysroot, cache_dir, NULL);
|
|
|
|
else
|
|
|
|
dir = FcStrCopyFilename (cache_dir);
|
|
|
|
if (!dir)
|
2012-04-18 05:55:23 +02:00
|
|
|
{
|
|
|
|
fprintf (stderr, "Fontconfig error: %s: out of memory\n", cache_dir);
|
2019-11-01 06:43:42 +01:00
|
|
|
ret = FcFalse;
|
|
|
|
goto bail;
|
2012-04-18 05:55:23 +02:00
|
|
|
}
|
2013-02-06 11:35:30 +01:00
|
|
|
if (access ((char *) dir, W_OK) != 0)
|
2012-04-18 05:55:23 +02:00
|
|
|
{
|
|
|
|
if (verbose || FcDebug () & FC_DBG_CACHE)
|
2013-02-06 11:35:30 +01:00
|
|
|
printf ("%s: not cleaning %s cache directory\n", dir,
|
|
|
|
access ((char *) dir, F_OK) == 0 ? "unwritable" : "non-existent");
|
2012-04-18 05:55:23 +02:00
|
|
|
goto bail0;
|
|
|
|
}
|
|
|
|
if (verbose || FcDebug () & FC_DBG_CACHE)
|
2013-02-06 11:35:30 +01:00
|
|
|
printf ("%s: cleaning cache directory\n", dir);
|
|
|
|
d = opendir ((char *) dir);
|
2012-04-18 05:55:23 +02:00
|
|
|
if (!d)
|
|
|
|
{
|
2013-02-06 11:35:30 +01:00
|
|
|
perror ((char *) dir);
|
2012-04-18 05:55:23 +02:00
|
|
|
ret = FcFalse;
|
|
|
|
goto bail0;
|
|
|
|
}
|
|
|
|
while ((ent = readdir (d)))
|
|
|
|
{
|
|
|
|
FcChar8 *file_name;
|
|
|
|
const FcChar8 *target_dir;
|
|
|
|
|
|
|
|
if (ent->d_name[0] == '.')
|
|
|
|
continue;
|
|
|
|
/* skip cache files for different architectures and */
|
|
|
|
/* files which are not cache files at all */
|
|
|
|
if (strlen(ent->d_name) != 32 + strlen ("-" FC_ARCHITECTURE FC_CACHE_SUFFIX) ||
|
|
|
|
strcmp(ent->d_name + 32, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX))
|
|
|
|
continue;
|
|
|
|
|
2013-02-06 11:35:30 +01:00
|
|
|
file_name = FcStrBuildFilename (dir, (FcChar8 *)ent->d_name, NULL);
|
2012-04-18 05:55:23 +02:00
|
|
|
if (!file_name)
|
|
|
|
{
|
2013-02-06 11:35:30 +01:00
|
|
|
fprintf (stderr, "Fontconfig error: %s: allocation failure\n", dir);
|
2012-04-18 05:55:23 +02:00
|
|
|
ret = FcFalse;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
remove = FcFalse;
|
|
|
|
cache = FcDirCacheLoadFile (file_name, NULL);
|
|
|
|
if (!cache)
|
|
|
|
{
|
|
|
|
if (verbose || FcDebug () & FC_DBG_CACHE)
|
2013-02-06 11:35:30 +01:00
|
|
|
printf ("%s: invalid cache file: %s\n", dir, ent->d_name);
|
2012-04-18 05:55:23 +02:00
|
|
|
remove = FcTrue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-06-17 13:08:24 +02:00
|
|
|
FcChar8 *s;
|
|
|
|
|
2012-04-18 05:55:23 +02:00
|
|
|
target_dir = FcCacheDir (cache);
|
2014-06-17 13:08:24 +02:00
|
|
|
if (sysroot)
|
|
|
|
s = FcStrBuildFilename (sysroot, target_dir, NULL);
|
|
|
|
else
|
|
|
|
s = FcStrdup (target_dir);
|
|
|
|
if (stat ((char *) s, &target_stat) < 0)
|
2012-04-18 05:55:23 +02:00
|
|
|
{
|
|
|
|
if (verbose || FcDebug () & FC_DBG_CACHE)
|
|
|
|
printf ("%s: %s: missing directory: %s \n",
|
2014-06-17 13:08:24 +02:00
|
|
|
dir, ent->d_name, s);
|
2012-04-18 05:55:23 +02:00
|
|
|
remove = FcTrue;
|
|
|
|
}
|
2013-01-16 14:30:44 +01:00
|
|
|
FcDirCacheUnload (cache);
|
2014-06-17 13:08:24 +02:00
|
|
|
FcStrFree (s);
|
2012-04-18 05:55:23 +02:00
|
|
|
}
|
|
|
|
if (remove)
|
|
|
|
{
|
|
|
|
if (unlink ((char *) file_name) < 0)
|
|
|
|
{
|
|
|
|
perror ((char *) file_name);
|
|
|
|
ret = FcFalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FcStrFree (file_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
closedir (d);
|
2019-11-01 06:43:42 +01:00
|
|
|
bail0:
|
2013-02-06 11:35:30 +01:00
|
|
|
FcStrFree (dir);
|
2019-11-01 06:43:42 +01:00
|
|
|
bail:
|
|
|
|
FcConfigDestroy (config);
|
2012-04-18 05:55:23 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-08-14 10:17:34 +02:00
|
|
|
int
|
|
|
|
FcDirCacheLock (const FcChar8 *dir,
|
|
|
|
FcConfig *config)
|
|
|
|
{
|
|
|
|
FcChar8 *cache_hashed = NULL;
|
|
|
|
FcChar8 cache_base[CACHEBASE_LEN];
|
|
|
|
FcStrList *list;
|
|
|
|
FcChar8 *cache_dir;
|
|
|
|
const FcChar8 *sysroot = FcConfigGetSysRoot (config);
|
|
|
|
int fd = -1;
|
|
|
|
|
Replace UUID file mechanism with per-directory 'map' attribute [v2]
The UUID files would be placed in each font directory to provide the
unique cache name, independent of path, for that directory. The UUID
files are undesireable for a couple of reasons:
1) They must be placed in the font directories to be useful. This
requires modifying the font directories themselves, introducing
potential visible timestamp changes when running multiple
applications, and makes the cache processing inconsistent between
applications with permission to write to the font directories and
applications without such permission.
2) The UUID contents were generated randomly, which makes the font
cache not reproducible across multiple runs.
One proposed fix for 2) is to make the UUID dependent on the font
directory path, but once we do that, we can simply use the font
directory path itself as the key as the original MD5-based font cache
naming mechanism did.
The goal of the UUID file mechanism was to fix startup time of
flatpaks; as the font path names inside the flatpak did not match the
font path names in the base system, the font cache would need to be
reconstructed the first time the flatpak was launched.
The new mechanism for doing this is to allow each '<dir>' element in
the configuration include a 'map' attribute. When looking for a cache
file for a particular directory, if the directory name starts with the
contents of the <dir> element, that portion of the name will be
replaced with the value of the 'map' attribute.
Outside of the flatpak, nothing need change -- fontconfig will build
cache files using real directory names.
Inside the flatpak, the custom fonts.conf file will now include
mappings such as this:
<dir map="/usr/share/fonts">/run/host/fonts</dir>
When scanning the directory /run/host/fonts/ttf, fontconfig will
use the name /usr/share/fonts/ttf as the source for building the cache
file name.
The existing FC_FILE replacement code used for the UUID-based
implementation continues to correctly adapt font path names seen by
applications.
v2:
Leave FcDirCacheCreateUUID stub around to avoid removing
public API function.
Document 'map' attribute of <dir> element in
fontconfig-user.sgml
Suggested-by: Akira TAGOH <akira@tagoh.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
2018-10-30 00:39:05 +01:00
|
|
|
FcDirCacheBasenameMD5 (config, dir, cache_base);
|
2015-08-14 10:17:34 +02:00
|
|
|
list = FcStrListCreate (config->cacheDirs);
|
|
|
|
if (!list)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while ((cache_dir = FcStrListNext (list)))
|
|
|
|
{
|
|
|
|
if (sysroot)
|
|
|
|
cache_hashed = FcStrBuildFilename (sysroot, cache_dir, cache_base, NULL);
|
|
|
|
else
|
|
|
|
cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL);
|
|
|
|
if (!cache_hashed)
|
|
|
|
break;
|
|
|
|
fd = FcOpen ((const char *)cache_hashed, O_RDWR);
|
2016-05-28 08:44:10 +02:00
|
|
|
FcStrFree (cache_hashed);
|
2015-08-14 10:17:34 +02:00
|
|
|
/* No caches in that directory. simply retry with another one */
|
|
|
|
if (fd != -1)
|
|
|
|
{
|
2015-10-13 06:06:54 +02:00
|
|
|
#if defined(_WIN32)
|
|
|
|
if (_locking (fd, _LK_LOCK, 1) == -1)
|
|
|
|
goto bail;
|
|
|
|
#else
|
2015-08-14 10:17:34 +02:00
|
|
|
struct flock fl;
|
|
|
|
|
|
|
|
fl.l_type = F_WRLCK;
|
|
|
|
fl.l_whence = SEEK_SET;
|
|
|
|
fl.l_start = 0;
|
|
|
|
fl.l_len = 0;
|
|
|
|
fl.l_pid = getpid ();
|
|
|
|
if (fcntl (fd, F_SETLKW, &fl) == -1)
|
|
|
|
goto bail;
|
2015-10-13 06:06:54 +02:00
|
|
|
#endif
|
2015-08-14 10:17:34 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-05-20 14:30:44 +02:00
|
|
|
FcStrListDone (list);
|
2015-08-14 10:17:34 +02:00
|
|
|
return fd;
|
|
|
|
bail:
|
2016-05-28 08:44:10 +02:00
|
|
|
FcStrListDone (list);
|
2015-08-14 10:17:34 +02:00
|
|
|
if (fd != -1)
|
|
|
|
close (fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
FcDirCacheUnlock (int fd)
|
|
|
|
{
|
|
|
|
if (fd != -1)
|
|
|
|
{
|
2015-10-13 06:06:54 +02:00
|
|
|
#if defined(_WIN32)
|
|
|
|
_locking (fd, _LK_UNLCK, 1);
|
|
|
|
#else
|
|
|
|
struct flock fl;
|
|
|
|
|
2015-08-14 10:17:34 +02:00
|
|
|
fl.l_type = F_UNLCK;
|
|
|
|
fl.l_whence = SEEK_SET;
|
|
|
|
fl.l_start = 0;
|
|
|
|
fl.l_len = 0;
|
|
|
|
fl.l_pid = getpid ();
|
|
|
|
fcntl (fd, F_SETLK, &fl);
|
2015-10-13 06:06:54 +02:00
|
|
|
#endif
|
2015-08-14 10:17:34 +02:00
|
|
|
close (fd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-09-04 09:47:07 +02:00
|
|
|
/*
|
|
|
|
* Hokey little macro trick to permit the definitions of C functions
|
|
|
|
* with the same name as CPP macros
|
|
|
|
*/
|
2006-12-02 22:36:56 +01:00
|
|
|
#define args1(x) (x)
|
|
|
|
#define args2(x,y) (x,y)
|
2006-09-04 09:47:07 +02:00
|
|
|
|
|
|
|
const FcChar8 *
|
2006-12-02 22:36:56 +01:00
|
|
|
FcCacheDir args1(const FcCache *c)
|
2006-09-04 09:47:07 +02:00
|
|
|
{
|
|
|
|
return FcCacheDir (c);
|
|
|
|
}
|
|
|
|
|
|
|
|
FcFontSet *
|
2006-12-02 22:36:56 +01:00
|
|
|
FcCacheCopySet args1(const FcCache *c)
|
2006-09-04 09:47:07 +02:00
|
|
|
{
|
|
|
|
FcFontSet *old = FcCacheSet (c);
|
|
|
|
FcFontSet *new = FcFontSetCreate ();
|
|
|
|
int i;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-09-04 09:47:07 +02:00
|
|
|
if (!new)
|
|
|
|
return NULL;
|
|
|
|
for (i = 0; i < old->nfont; i++)
|
2006-09-07 23:22:16 +02:00
|
|
|
{
|
|
|
|
FcPattern *font = FcFontSetFont (old, i);
|
|
|
|
|
|
|
|
FcPatternReference (font);
|
|
|
|
if (!FcFontSetAdd (new, font))
|
2006-09-04 09:47:07 +02:00
|
|
|
{
|
|
|
|
FcFontSetDestroy (new);
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-09-07 23:22:16 +02:00
|
|
|
}
|
2006-09-04 09:47:07 +02:00
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
const FcChar8 *
|
2006-12-02 22:36:56 +01:00
|
|
|
FcCacheSubdir args2(const FcCache *c, int i)
|
2006-09-04 09:47:07 +02:00
|
|
|
{
|
|
|
|
return FcCacheSubdir (c, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-12-02 22:36:56 +01:00
|
|
|
FcCacheNumSubdir args1(const FcCache *c)
|
2006-09-04 09:47:07 +02:00
|
|
|
{
|
|
|
|
return c->dirs_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-12-02 22:36:56 +01:00
|
|
|
FcCacheNumFont args1(const FcCache *c)
|
2006-09-04 09:47:07 +02:00
|
|
|
{
|
|
|
|
return FcCacheSet(c)->nfont;
|
|
|
|
}
|
|
|
|
|
2012-03-28 10:28:06 +02:00
|
|
|
FcBool
|
|
|
|
FcDirCacheCreateTagFile (const FcChar8 *cache_dir)
|
|
|
|
{
|
|
|
|
FcChar8 *cache_tag;
|
|
|
|
int fd;
|
|
|
|
FILE *fp;
|
|
|
|
FcAtomic *atomic;
|
|
|
|
static const FcChar8 cache_tag_contents[] =
|
|
|
|
"Signature: 8a477f597d28d172789f06886806bc55\n"
|
|
|
|
"# This file is a cache directory tag created by fontconfig.\n"
|
|
|
|
"# For information about cache directory tags, see:\n"
|
|
|
|
"# http://www.brynosaurus.com/cachedir/\n";
|
|
|
|
static size_t cache_tag_contents_size = sizeof (cache_tag_contents) - 1;
|
|
|
|
FcBool ret = FcFalse;
|
|
|
|
|
|
|
|
if (!cache_dir)
|
|
|
|
return FcFalse;
|
|
|
|
|
2012-08-31 05:39:38 +02:00
|
|
|
if (access ((char *) cache_dir, W_OK) == 0)
|
2012-03-28 10:28:06 +02:00
|
|
|
{
|
|
|
|
/* Create CACHEDIR.TAG */
|
2013-02-06 11:35:30 +01:00
|
|
|
cache_tag = FcStrBuildFilename (cache_dir, "CACHEDIR.TAG", NULL);
|
2012-03-28 10:28:06 +02:00
|
|
|
if (!cache_tag)
|
|
|
|
return FcFalse;
|
|
|
|
atomic = FcAtomicCreate ((FcChar8 *)cache_tag);
|
|
|
|
if (!atomic)
|
|
|
|
goto bail1;
|
|
|
|
if (!FcAtomicLock (atomic))
|
|
|
|
goto bail2;
|
2012-12-06 12:01:52 +01:00
|
|
|
fd = FcOpen((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT, 0644);
|
2012-03-28 10:28:06 +02:00
|
|
|
if (fd == -1)
|
|
|
|
goto bail3;
|
|
|
|
fp = fdopen(fd, "wb");
|
|
|
|
if (fp == NULL)
|
|
|
|
goto bail3;
|
|
|
|
|
|
|
|
fwrite(cache_tag_contents, cache_tag_contents_size, sizeof (FcChar8), fp);
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
if (!FcAtomicReplaceOrig(atomic))
|
|
|
|
goto bail3;
|
|
|
|
|
|
|
|
ret = FcTrue;
|
|
|
|
bail3:
|
|
|
|
FcAtomicUnlock (atomic);
|
|
|
|
bail2:
|
|
|
|
FcAtomicDestroy (atomic);
|
|
|
|
bail1:
|
|
|
|
FcStrFree (cache_tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FcDebug () & FC_DBG_CACHE)
|
|
|
|
{
|
|
|
|
if (ret)
|
|
|
|
printf ("Created CACHEDIR.TAG at %s\n", cache_dir);
|
|
|
|
else
|
|
|
|
printf ("Unable to create CACHEDIR.TAG at %s\n", cache_dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-11-01 06:43:42 +01:00
|
|
|
FcCacheCreateTagFile (FcConfig *config)
|
2012-03-28 10:28:06 +02:00
|
|
|
{
|
2013-02-06 11:35:30 +01:00
|
|
|
FcChar8 *cache_dir = NULL, *d = NULL;
|
2012-03-28 10:28:06 +02:00
|
|
|
FcStrList *list;
|
2019-11-01 06:43:42 +01:00
|
|
|
const FcChar8 *sysroot;
|
|
|
|
|
|
|
|
config = FcConfigReference (config);
|
|
|
|
if (!config)
|
|
|
|
return;
|
|
|
|
sysroot = FcConfigGetSysRoot (config);
|
2012-03-28 10:28:06 +02:00
|
|
|
|
|
|
|
list = FcConfigGetCacheDirs (config);
|
|
|
|
if (!list)
|
2019-11-01 06:43:42 +01:00
|
|
|
goto bail;
|
2012-03-28 10:28:06 +02:00
|
|
|
|
|
|
|
while ((cache_dir = FcStrListNext (list)))
|
|
|
|
{
|
2013-02-06 11:35:30 +01:00
|
|
|
if (d)
|
|
|
|
FcStrFree (d);
|
|
|
|
if (sysroot)
|
|
|
|
d = FcStrBuildFilename (sysroot, cache_dir, NULL);
|
|
|
|
else
|
|
|
|
d = FcStrCopyFilename (cache_dir);
|
|
|
|
if (FcDirCacheCreateTagFile (d))
|
2012-03-28 10:28:06 +02:00
|
|
|
break;
|
|
|
|
}
|
2013-02-06 11:35:30 +01:00
|
|
|
if (d)
|
|
|
|
FcStrFree (d);
|
2012-03-28 10:28:06 +02:00
|
|
|
FcStrListDone (list);
|
2019-11-01 06:43:42 +01:00
|
|
|
bail:
|
|
|
|
FcConfigDestroy (config);
|
2012-03-28 10:28:06 +02:00
|
|
|
}
|
|
|
|
|
2006-09-05 11:24:01 +02:00
|
|
|
#define __fccache__
|
|
|
|
#include "fcaliastail.h"
|
|
|
|
#undef __fccache__
|