diff --git a/src/fccache.c b/src/fccache.c index fc3ed41..5a8720b 100644 --- a/src/fccache.c +++ b/src/fccache.c @@ -1142,6 +1142,70 @@ FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose) return ret; } +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; + + FcDirCacheBasename (dir, cache_base); + 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); + /* No caches in that directory. simply retry with another one */ + if (fd != -1) + { + 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; + break; + } + } + return fd; +bail: + if (fd != -1) + close (fd); + return -1; +} + +void +FcDirCacheUnlock (int fd) +{ + struct flock fl; + + if (fd != -1) + { + 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); + close (fd); + } +} + /* * Hokey little macro trick to permit the definitions of C functions * with the same name as CPP macros diff --git a/src/fcdir.c b/src/fcdir.c index 2e7f0dc..f4807dd 100644 --- a/src/fcdir.c +++ b/src/fcdir.c @@ -332,6 +332,7 @@ FcDirCacheScan (const FcChar8 *dir, FcConfig *config) struct stat dir_stat; const FcChar8 *sysroot = FcConfigGetSysRoot (config); FcChar8 *d; + int fd = -1; if (sysroot) d = FcStrBuildFilename (sysroot, dir, NULL); @@ -352,6 +353,7 @@ FcDirCacheScan (const FcChar8 *dir, FcConfig *config) if (!dirs) goto bail1; + fd = FcDirCacheLock (dir, config); /* * Scan the dir */ @@ -371,6 +373,7 @@ FcDirCacheScan (const FcChar8 *dir, FcConfig *config) FcDirCacheWrite (cache, config); bail2: + FcDirCacheUnlock (fd); FcStrSetDestroy (dirs); bail1: FcFontSetDestroy (set); @@ -389,6 +392,7 @@ FcDirCacheRescan (const FcChar8 *dir, FcConfig *config) FcStrSet *dirs; const FcChar8 *sysroot = FcConfigGetSysRoot (config); FcChar8 *d = NULL; + int fd = -1; cache = FcDirCacheLoad (dir, config, NULL); if (!cache) @@ -404,6 +408,7 @@ FcDirCacheRescan (const FcChar8 *dir, FcConfig *config) if (!dirs) goto bail; + fd = FcDirCacheLock (dir, config); /* * Scan the dir */ @@ -422,6 +427,7 @@ FcDirCacheRescan (const FcChar8 *dir, FcConfig *config) FcDirCacheWrite (new, config); bail1: + FcDirCacheUnlock (fd); FcStrSetDestroy (dirs); bail: if (d) diff --git a/src/fcint.h b/src/fcint.h index 15e22fd..76becec 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -590,6 +590,13 @@ FcCacheFini (void); FcPrivate void FcDirCacheReference (FcCache *cache, int nref); +FcPrivate int +FcDirCacheLock (const FcChar8 *dir, + FcConfig *config); + +FcPrivate void +FcDirCacheUnlock (int fd); + /* fccfg.c */ FcPrivate FcBool