+FcBool
+FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose)
+{
+ DIR *d;
+ struct dirent *ent;
+ FcChar8 *dir;
+ FcBool ret = FcTrue;
+ FcBool remove;
+ FcCache *cache;
+ struct stat target_stat;
+ const FcChar8 *sysroot;
+
+ /* 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)
+ {
+ fprintf (stderr, "Fontconfig error: %s: out of memory\n", cache_dir);
+ return FcFalse;
+ }
+ if (access ((char *) dir, W_OK) != 0)
+ {
+ if (verbose || FcDebug () & FC_DBG_CACHE)
+ printf ("%s: not cleaning %s cache directory\n", dir,
+ access ((char *) dir, F_OK) == 0 ? "unwritable" : "non-existent");
+ goto bail0;
+ }
+ if (verbose || FcDebug () & FC_DBG_CACHE)
+ printf ("%s: cleaning cache directory\n", dir);
+ d = opendir ((char *) dir);
+ if (!d)
+ {
+ perror ((char *) dir);
+ 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;
+
+ file_name = FcStrBuildFilename (dir, (FcChar8 *)ent->d_name, NULL);
+ if (!file_name)
+ {
+ fprintf (stderr, "Fontconfig error: %s: allocation failure\n", dir);
+ ret = FcFalse;
+ break;
+ }
+ remove = FcFalse;
+ cache = FcDirCacheLoadFile (file_name, NULL);
+ if (!cache)
+ {
+ if (verbose || FcDebug () & FC_DBG_CACHE)
+ printf ("%s: invalid cache file: %s\n", dir, ent->d_name);
+ remove = FcTrue;
+ }
+ else
+ {
+ FcChar8 *s;
+
+ target_dir = FcCacheDir (cache);
+ if (sysroot)
+ s = FcStrBuildFilename (sysroot, target_dir, NULL);
+ else
+ s = FcStrdup (target_dir);
+ if (stat ((char *) s, &target_stat) < 0)
+ {
+ if (verbose || FcDebug () & FC_DBG_CACHE)
+ printf ("%s: %s: missing directory: %s \n",
+ dir, ent->d_name, s);
+ remove = FcTrue;
+ }
+ FcDirCacheUnload (cache);
+ FcStrFree (s);
+ }
+ if (remove)
+ {
+ if (unlink ((char *) file_name) < 0)
+ {
+ perror ((char *) file_name);
+ ret = FcFalse;
+ }
+ }
+ FcStrFree (file_name);
+ }
+
+ closedir (d);
+ bail0:
+ FcStrFree (dir);
+
+ 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);
+ FcStrFree (cache_hashed);
+ /* No caches in that directory. simply retry with another one */
+ if (fd != -1)
+ {
+#if defined(_WIN32)
+ if (_locking (fd, _LK_LOCK, 1) == -1)
+ goto bail;
+#else
+ 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;
+#endif
+ break;
+ }
+ }
+ FcStrListDone (list);
+ return fd;
+bail:
+ FcStrListDone (list);
+ if (fd != -1)
+ close (fd);
+ return -1;
+}
+
+void
+FcDirCacheUnlock (int fd)
+{
+ if (fd != -1)
+ {
+#if defined(_WIN32)
+ _locking (fd, _LK_UNLCK, 1);
+#else
+ struct flock fl;
+
+ 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);
+#endif
+ close (fd);
+ }
+}
+