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"
|
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>
|
2005-08-24 08:21:30 +02:00
|
|
|
#include <dirent.h>
|
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>
|
2017-12-18 13:26:29 +01:00
|
|
|
#include <sys/time.h>
|
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
|
2018-06-11 10:03:17 +02:00
|
|
|
const FcChar8 *sysroot = FcConfigGetSysRoot (config);
|
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
|
|
|
|
|
|
|
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
|
2018-06-11 10:03:17 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-12-09 17:36:45 +01:00
|
|
|
struct MD5Context {
|
|
|
|
FcChar32 buf[4];
|
|
|
|
FcChar32 bits[2];
|
|
|
|
unsigned char in[64];
|
|
|
|
};
|
|
|
|
|
|
|
|
static void MD5Init(struct MD5Context *ctx);
|
2007-10-18 13:13:51 +02:00
|
|
|
static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len);
|
2005-12-09 17:36:45 +01:00
|
|
|
static void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
|
|
|
|
static void MD5Transform(FcChar32 buf[4], FcChar32 in[16]);
|
|
|
|
|
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;
|
2013-01-03 00:35:56 +01:00
|
|
|
(void) fc_atomic_ptr_cmpexch (&static_status, NULL, (void *) 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;
|
2013-02-06 11:35:30 +01:00
|
|
|
const FcChar8 *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)
|
|
|
|
return FcFalse;
|
|
|
|
|
|
|
|
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)
|
|
|
|
return FcFalse;
|
2005-08-25 09:38:02 +02:00
|
|
|
return FcTrue;
|
|
|
|
}
|
|
|
|
|
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,
|
2007-10-18 13:13:51 +02:00
|
|
|
struct stat *dir_stat, 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);
|
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;
|
2013-02-06 11:35:30 +01:00
|
|
|
|
2019-04-04 12:59:47 +02:00
|
|
|
retry:
|
|
|
|
#endif
|
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;
|
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) {
|
2014-06-17 13:08:24 +02:00
|
|
|
ret = (*callback) (config, fd, &file_stat, &dir_stat, 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)
|
|
|
|
*cache_file_ret = cache_hashed;
|
|
|
|
else
|
|
|
|
FcStrFree (cache_hashed);
|
|
|
|
break;
|
2006-08-28 02:04:01 +02:00
|
|
|
}
|
|
|
|
}
|
2019-04-04 12:59:47 +02:00
|
|
|
#ifndef _WIN32
|
|
|
|
else if (!retried)
|
|
|
|
{
|
|
|
|
retried = FcTrue;
|
|
|
|
FcDirCacheBasenameUUID (config, dir, cache_base);
|
|
|
|
if (cache_base[0] != 0)
|
|
|
|
{
|
|
|
|
FcStrFree (cache_hashed);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2006-08-31 20:56:43 +02:00
|
|
|
FcStrFree (cache_hashed);
|
2006-08-04 18:13:00 +02:00
|
|
|
}
|
|
|
|
FcStrListDone (list);
|
2010-04-12 18:18:50 +02:00
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
FcMutexUnlock (cache_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
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++)
|
|
|
|
assert (fcCacheChains[i] == NULL);
|
|
|
|
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
|
|
|
|
|
|
|
|
return 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
|
2014-06-17 13:08:24 +02:00
|
|
|
FcDirCacheMapHelper (FcConfig *config, int fd, struct stat *fd_stat, struct stat *dir_stat, 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);
|
2006-09-01 10:15:14 +02:00
|
|
|
|
|
|
|
if (!cache)
|
|
|
|
return FcFalse;
|
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
|
|
|
|
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))
|
2006-08-31 07:23:25 +02:00
|
|
|
return NULL;
|
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;
|
|
|
|
FcCache *cache;
|
2007-11-03 22:16:29 +01:00
|
|
|
struct stat my_file_stat;
|
2006-08-28 07:24:39 +02:00
|
|
|
|
2007-11-03 22:16:29 +01:00
|
|
|
if (!file_stat)
|
|
|
|
file_stat = &my_file_stat;
|
2006-09-01 10:15:14 +02:00
|
|
|
fd = FcDirCacheOpenFile (cache_file, file_stat);
|
|
|
|
if (fd < 0)
|
|
|
|
return NULL;
|
2014-06-17 13:08:24 +02:00
|
|
|
cache = FcDirCacheMapFd (FcConfigGetCurrent (), fd, file_stat, NULL);
|
2006-09-01 10:15:14 +02:00
|
|
|
close (fd);
|
|
|
|
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,
|
|
|
|
"Fontconfig: SOURCE_DATE_EPOCH: strtoull: %s: %llu\n",
|
|
|
|
strerror(errno), epoch);
|
|
|
|
else if (*endptr != '\0')
|
|
|
|
fprintf (stderr,
|
|
|
|
"Fontconfig: SOURCE_DATE_EPOCH has trailing garbage\n");
|
|
|
|
else if (epoch > ULONG_MAX)
|
|
|
|
fprintf (stderr,
|
|
|
|
"Fontconfig: SOURCE_DATE_EPOCH must be <= %lu but saw: %llu\n",
|
|
|
|
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
|
2014-06-17 13:08:24 +02:00
|
|
|
FcDirCacheValidateHelper (FcConfig *config, int fd, struct stat *fd_stat, struct stat *dir_stat, 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;
|
2010-04-12 18:18:50 +02:00
|
|
|
|
2006-08-31 23:38:18 +02:00
|
|
|
config = FcConfigGetCurrent ();
|
|
|
|
if (!config)
|
|
|
|
return FcFalse;
|
|
|
|
|
|
|
|
return FcDirCacheValidConfig (dir, config);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
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;
|
2012-04-18 05:55:23 +02:00
|
|
|
|
2013-02-06 11:35:30 +01:00
|
|
|
/* FIXME: this API needs to support non-current FcConfig */
|
|
|
|
sysroot = FcConfigGetSysRoot (NULL);
|
|
|
|
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);
|
|
|
|
return FcFalse;
|
|
|
|
}
|
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);
|
|
|
|
bail0:
|
2013-02-06 11:35:30 +01:00
|
|
|
FcStrFree (dir);
|
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;
|
|
|
|
}
|
|
|
|
|
2005-12-09 17:36:45 +01:00
|
|
|
/*
|
|
|
|
* This code implements the MD5 message-digest algorithm.
|
|
|
|
* The algorithm is due to Ron Rivest. This code was
|
|
|
|
* written by Colin Plumb in 1993, no copyright is claimed.
|
|
|
|
* This code is in the public domain; do with it what you wish.
|
|
|
|
*
|
|
|
|
* Equivalent code is available from RSA Data Security, Inc.
|
|
|
|
* This code has been tested against that, and is equivalent,
|
|
|
|
* except that you don't need to include two pages of legalese
|
|
|
|
* with every copy.
|
|
|
|
*
|
|
|
|
* To compute the message digest of a chunk of bytes, declare an
|
|
|
|
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
|
|
|
* needed on buffers full of bytes, and then call MD5Final, which
|
|
|
|
* will fill a supplied 16-byte array with the digest.
|
|
|
|
*/
|
|
|
|
|
2019-06-10 12:57:05 +02:00
|
|
|
#ifndef WORDS_BIGENDIAN
|
2005-12-09 17:36:45 +01:00
|
|
|
#define byteReverse(buf, len) /* Nothing */
|
|
|
|
#else
|
|
|
|
/*
|
|
|
|
* Note: this code is harmless on little-endian machines.
|
|
|
|
*/
|
|
|
|
void byteReverse(unsigned char *buf, unsigned longs)
|
|
|
|
{
|
|
|
|
FcChar32 t;
|
|
|
|
do {
|
|
|
|
t = (FcChar32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
|
|
|
|
((unsigned) buf[1] << 8 | buf[0]);
|
|
|
|
*(FcChar32 *) buf = t;
|
|
|
|
buf += 4;
|
|
|
|
} while (--longs);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
|
|
|
* initialization constants.
|
|
|
|
*/
|
|
|
|
static void MD5Init(struct MD5Context *ctx)
|
|
|
|
{
|
|
|
|
ctx->buf[0] = 0x67452301;
|
|
|
|
ctx->buf[1] = 0xefcdab89;
|
|
|
|
ctx->buf[2] = 0x98badcfe;
|
|
|
|
ctx->buf[3] = 0x10325476;
|
|
|
|
|
|
|
|
ctx->bits[0] = 0;
|
|
|
|
ctx->bits[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Update context to reflect the concatenation of another buffer full
|
|
|
|
* of bytes.
|
|
|
|
*/
|
2007-10-18 13:13:51 +02:00
|
|
|
static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len)
|
2005-12-09 17:36:45 +01:00
|
|
|
{
|
|
|
|
FcChar32 t;
|
|
|
|
|
|
|
|
/* Update bitcount */
|
|
|
|
|
|
|
|
t = ctx->bits[0];
|
|
|
|
if ((ctx->bits[0] = t + ((FcChar32) len << 3)) < t)
|
|
|
|
ctx->bits[1]++; /* Carry from low to high */
|
|
|
|
ctx->bits[1] += len >> 29;
|
|
|
|
|
|
|
|
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
|
|
|
|
|
|
|
/* Handle any leading odd-sized chunks */
|
|
|
|
|
|
|
|
if (t) {
|
|
|
|
unsigned char *p = (unsigned char *) ctx->in + t;
|
|
|
|
|
|
|
|
t = 64 - t;
|
|
|
|
if (len < t) {
|
|
|
|
memcpy(p, buf, len);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
memcpy(p, buf, t);
|
|
|
|
byteReverse(ctx->in, 16);
|
|
|
|
MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
|
|
|
|
buf += t;
|
|
|
|
len -= t;
|
|
|
|
}
|
|
|
|
/* Process data in 64-byte chunks */
|
|
|
|
|
|
|
|
while (len >= 64) {
|
|
|
|
memcpy(ctx->in, buf, 64);
|
|
|
|
byteReverse(ctx->in, 16);
|
|
|
|
MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
|
|
|
|
buf += 64;
|
|
|
|
len -= 64;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle any remaining bytes of data. */
|
|
|
|
|
|
|
|
memcpy(ctx->in, buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-04-12 18:18:50 +02:00
|
|
|
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
2005-12-09 17:36:45 +01:00
|
|
|
* 1 0* (64-bit count of bits processed, MSB-first)
|
|
|
|
*/
|
|
|
|
static void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
|
|
|
|
{
|
|
|
|
unsigned count;
|
|
|
|
unsigned char *p;
|
|
|
|
|
|
|
|
/* Compute number of bytes mod 64 */
|
|
|
|
count = (ctx->bits[0] >> 3) & 0x3F;
|
|
|
|
|
|
|
|
/* Set the first char of padding to 0x80. This is safe since there is
|
|
|
|
always at least one byte free */
|
|
|
|
p = ctx->in + count;
|
|
|
|
*p++ = 0x80;
|
|
|
|
|
|
|
|
/* Bytes of padding needed to make 64 bytes */
|
|
|
|
count = 64 - 1 - count;
|
|
|
|
|
|
|
|
/* Pad out to 56 mod 64 */
|
|
|
|
if (count < 8) {
|
|
|
|
/* Two lots of padding: Pad the first block to 64 bytes */
|
|
|
|
memset(p, 0, count);
|
|
|
|
byteReverse(ctx->in, 16);
|
|
|
|
MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
|
|
|
|
|
|
|
|
/* Now fill the next block with 56 bytes */
|
|
|
|
memset(ctx->in, 0, 56);
|
|
|
|
} else {
|
|
|
|
/* Pad block to 56 bytes */
|
|
|
|
memset(p, 0, count - 8);
|
|
|
|
}
|
|
|
|
byteReverse(ctx->in, 14);
|
|
|
|
|
|
|
|
/* Append length in bits and transform */
|
|
|
|
((FcChar32 *) ctx->in)[14] = ctx->bits[0];
|
|
|
|
((FcChar32 *) ctx->in)[15] = ctx->bits[1];
|
|
|
|
|
|
|
|
MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
|
|
|
|
byteReverse((unsigned char *) ctx->buf, 4);
|
|
|
|
memcpy(digest, ctx->buf, 16);
|
2011-09-24 19:52:05 +02:00
|
|
|
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
|
2005-12-09 17:36:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* The four core functions - F1 is optimized somewhat */
|
|
|
|
|
|
|
|
/* #define F1(x, y, z) (x & y | ~x & z) */
|
|
|
|
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
|
|
|
#define F2(x, y, z) F1(z, x, y)
|
|
|
|
#define F3(x, y, z) (x ^ y ^ z)
|
|
|
|
#define F4(x, y, z) (y ^ (x | ~z))
|
|
|
|
|
|
|
|
/* This is the central step in the MD5 algorithm. */
|
|
|
|
#define MD5STEP(f, w, x, y, z, data, s) \
|
|
|
|
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
|
|
|
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
|
|
|
* the data and converts bytes into longwords for this routine.
|
|
|
|
*/
|
|
|
|
static void MD5Transform(FcChar32 buf[4], FcChar32 in[16])
|
|
|
|
{
|
|
|
|
register FcChar32 a, b, c, d;
|
|
|
|
|
|
|
|
a = buf[0];
|
|
|
|
b = buf[1];
|
|
|
|
c = buf[2];
|
|
|
|
d = buf[3];
|
|
|
|
|
|
|
|
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
|
|
|
|
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
|
|
|
|
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
|
|
|
|
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
|
|
|
|
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
|
|
|
|
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
|
|
|
|
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
|
|
|
|
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
|
|
|
|
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
|
|
|
|
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
|
|
|
|
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
|
|
|
|
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
|
|
|
|
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
|
|
|
|
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
|
|
|
|
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
|
|
|
|
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
|
|
|
|
|
|
|
|
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
|
|
|
|
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
|
|
|
|
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
|
|
|
|
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
|
|
|
|
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
|
|
|
|
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
|
|
|
|
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
|
|
|
|
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
|
|
|
|
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
|
|
|
|
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
|
|
|
|
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
|
|
|
|
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
|
|
|
|
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
|
|
|
|
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
|
|
|
|
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
|
|
|
|
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
|
|
|
|
|
|
|
|
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
|
|
|
|
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
|
|
|
|
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
|
|
|
|
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
|
|
|
|
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
|
|
|
|
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
|
|
|
|
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
|
|
|
|
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
|
|
|
|
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
|
|
|
|
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
|
|
|
|
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
|
|
|
|
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
|
|
|
|
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
|
|
|
|
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
|
|
|
|
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
|
|
|
|
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
|
|
|
|
|
|
|
|
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
|
|
|
|
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
|
|
|
|
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
|
|
|
|
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
|
|
|
|
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
|
|
|
|
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
|
|
|
|
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
|
|
|
|
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
|
|
|
|
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
|
|
|
|
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
|
|
|
|
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
|
|
|
|
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
|
|
|
|
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
|
|
|
|
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
|
|
|
|
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
|
|
|
|
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
|
|
|
|
|
|
|
|
buf[0] += a;
|
|
|
|
buf[1] += b;
|
|
|
|
buf[2] += c;
|
|
|
|
buf[3] += d;
|
|
|
|
}
|
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
|
|
|
|
FcCacheCreateTagFile (const FcConfig *config)
|
|
|
|
{
|
2013-02-06 11:35:30 +01:00
|
|
|
FcChar8 *cache_dir = NULL, *d = NULL;
|
2012-03-28 10:28:06 +02:00
|
|
|
FcStrList *list;
|
2013-02-06 11:35:30 +01:00
|
|
|
const FcChar8 *sysroot = FcConfigGetSysRoot (config);
|
2012-03-28 10:28:06 +02:00
|
|
|
|
|
|
|
list = FcConfigGetCacheDirs (config);
|
|
|
|
if (!list)
|
|
|
|
return;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2006-09-05 11:24:01 +02:00
|
|
|
#define __fccache__
|
|
|
|
#include "fcaliastail.h"
|
|
|
|
#undef __fccache__
|