diff options
Diffstat (limited to 'fontconfig/src')
-rw-r--r-- | fontconfig/src/Makefile.am | 1 | ||||
-rw-r--r-- | fontconfig/src/fcatomic.c | 10 | ||||
-rw-r--r-- | fontconfig/src/fccache.c | 152 | ||||
-rw-r--r-- | fontconfig/src/fcdir.c | 2 | ||||
-rw-r--r-- | fontconfig/src/fcint.h | 26 | ||||
-rw-r--r-- | fontconfig/src/fcstat.c | 308 |
6 files changed, 349 insertions, 150 deletions
diff --git a/fontconfig/src/Makefile.am b/fontconfig/src/Makefile.am index 0bd0e3ded..65ec1e3bb 100644 --- a/fontconfig/src/Makefile.am +++ b/fontconfig/src/Makefile.am @@ -119,6 +119,7 @@ libfontconfig_la_SOURCES = \ fcname.c \ fcpat.c \ fcserialize.c \ + fcstat.c \ fcstr.c \ fcxml.c \ ftglue.h \ diff --git a/fontconfig/src/fcatomic.c b/fontconfig/src/fcatomic.c index 33c1cc628..4f6ab01f4 100644 --- a/fontconfig/src/fcatomic.c +++ b/fontconfig/src/fcatomic.c @@ -130,6 +130,13 @@ FcAtomicLock (FcAtomic *atomic) return FcFalse; } ret = link ((char *) atomic->tmp, (char *) atomic->lck); + if (ret < 0 && errno == EPERM) + { + /* the filesystem where atomic->lck points to may not supports + * the hard link. so better try to fallback + */ + ret = mkdir ((char *) atomic->lck, 0600); + } (void) unlink ((char *) atomic->tmp); #else ret = mkdir ((char *) atomic->lck, 0600); @@ -195,7 +202,8 @@ void FcAtomicUnlock (FcAtomic *atomic) { #ifdef HAVE_LINK - unlink ((char *) atomic->lck); + if (unlink ((char *) atomic->lck) == -1) + rmdir ((char *) atomic->lck); #else rmdir ((char *) atomic->lck); #endif diff --git a/fontconfig/src/fccache.c b/fontconfig/src/fccache.c index 882dd3eb5..9e582b911 100644 --- a/fontconfig/src/fccache.c +++ b/fontconfig/src/fccache.c @@ -37,21 +37,6 @@ # include <unistd.h> # include <sys/mman.h> #endif -#ifdef HAVE_SYS_VFS_H -#include <sys/vfs.h> -#endif -#ifdef HAVE_SYS_STATFS_H -#include <sys/statfs.h> -#endif -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> -#endif -#ifdef HAVE_SYS_MOUNT_H -#include <sys/mount.h> -#endif -#ifdef HAVE_MNTENT_H -#include <mntent.h> -#endif #ifndef O_BINARY #define O_BINARY 0 @@ -71,98 +56,9 @@ static void MD5Transform(FcChar32 buf[4], FcChar32 in[16]); #define CACHEBASE_LEN (1 + 32 + 1 + sizeof (FC_ARCHITECTURE) + sizeof (FC_CACHE_SUFFIX)) -#ifdef _WIN32 - -#include <windows.h> - -#ifdef __GNUC__ -typedef long long INT64; -#define EPOCH_OFFSET 11644473600ll -#else -#define EPOCH_OFFSET 11644473600i64 -typedef __int64 INT64; -#endif - -/* Workaround for problems in the stat() in the Microsoft C library: - * - * 1) stat() uses FindFirstFile() to get the file - * attributes. Unfortunately this API doesn't return correct values - * for modification time of a directory until some time after a file - * or subdirectory has been added to the directory. (This causes - * run-test.sh to fail, for instance.) GetFileAttributesEx() is - * better, it returns the updated timestamp right away. - * - * 2) stat() does some strange things related to backward - * compatibility with the local time timestamps on FAT volumes and - * daylight saving time. This causes problems after the switches - * to/from daylight saving time. See - * http://bugzilla.gnome.org/show_bug.cgi?id=154968 , especially - * comment #30, and http://www.codeproject.com/datetime/dstbugs.asp . - * We don't need any of that, FAT and Win9x are as good as dead. So - * just use the UTC timestamps from NTFS, converted to the Unix epoch. - */ - -int -FcStat (const FcChar8 *file, struct stat *statb) -{ - WIN32_FILE_ATTRIBUTE_DATA wfad; - char full_path_name[MAX_PATH]; - char *basename; - DWORD rc; - - if (!GetFileAttributesEx (file, GetFileExInfoStandard, &wfad)) - return -1; - - statb->st_dev = 0; - - /* Calculate a pseudo inode number as a hash of the full path name. - * Call GetLongPathName() to get the spelling of the path name as it - * is on disk. - */ - rc = GetFullPathName (file, sizeof (full_path_name), full_path_name, &basename); - if (rc == 0 || rc > sizeof (full_path_name)) - return -1; - - rc = GetLongPathName (full_path_name, full_path_name, sizeof (full_path_name)); - statb->st_ino = FcStringHash (full_path_name); - - statb->st_mode = _S_IREAD | _S_IWRITE; - statb->st_mode |= (statb->st_mode >> 3) | (statb->st_mode >> 6); - - if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - statb->st_mode |= _S_IFDIR; - else - statb->st_mode |= _S_IFREG; - - statb->st_nlink = 1; - statb->st_uid = statb->st_gid = 0; - statb->st_rdev = 0; - - if (wfad.nFileSizeHigh > 0) - return -1; - statb->st_size = wfad.nFileSizeLow; - - statb->st_atime = (*(INT64 *)&wfad.ftLastAccessTime)/10000000 - EPOCH_OFFSET; - statb->st_mtime = (*(INT64 *)&wfad.ftLastWriteTime)/10000000 - EPOCH_OFFSET; - statb->st_ctime = statb->st_mtime; - - return 0; -} - -#else - -int -FcStat (const FcChar8 *file, struct stat *statb) -{ - return stat ((char *) file, statb); -} - -#endif - static FcBool FcCacheIsMmapSafe (int fd) { - FcBool retval = FcTrue; static FcBool is_initialized = FcFalse; static FcBool is_env_available = FcFalse; static FcBool use_mmap = FcFalse; @@ -181,40 +77,8 @@ FcCacheIsMmapSafe (int fd) } if (is_env_available) return use_mmap; -#if defined(HAVE_FSTATVFS) && (defined(HAVE_STRUCT_STATVFS_F_BASETYPE) || defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME)) - struct statvfs buf; - - if (fstatvfs (fd, &buf) == 0) - { - const char *p; -#if defined(HAVE_STRUCT_STATVFS_F_BASETYPE) - p = buf.f_basetype; -#elif defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME) - p = buf.f_fstypename; -#endif - - if (strcmp (p, "nfs") == 0) - retval = FcFalse; - } -#elif defined(HAVE_FSTATFS) && (defined(HAVE_STRUCT_STATFS_F_FLAGS) || defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) || defined(__linux__)) - struct statfs buf; - - if (fstatfs (fd, &buf) == 0) - { -# if defined(HAVE_STRUCT_STATFS_F_FLAGS) && defined(MNT_LOCAL) - if (!(buf.f_flags & MNT_LOCAL)) -# elif defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) - if (strcmp (buf.f_fstypename, "nfs") == 0) -# elif defined(__linux__) - if (buf.f_type == 0x6969) /* nfs */ -# else -# error "BUG: No way to figure out with fstatfs()" -# endif - retval = FcFalse; - } -#endif - return retval; + return FcIsFsMmapSafe (fd); } static const char bin2hex[] = { '0', '1', '2', '3', @@ -317,7 +181,7 @@ FcDirCacheProcess (FcConfig *config, const FcChar8 *dir, struct stat file_stat, dir_stat; FcBool ret = FcFalse; - if (FcStat (dir, &dir_stat) < 0) + if (FcStatChecksum (dir, &dir_stat) < 0) return FcFalse; FcDirCacheBasename (dir, cache_base); @@ -644,14 +508,14 @@ FcCacheTimeValid (FcCache *cache, struct stat *dir_stat) if (!dir_stat) { - if (FcStat (FcCacheDir (cache), &dir_static) < 0) + if (FcStatChecksum (FcCacheDir (cache), &dir_static) < 0) return FcFalse; dir_stat = &dir_static; } if (FcDebug () & FC_DBG_CACHE) - printf ("FcCacheTimeValid dir \"%s\" cache time %d dir time %d\n", - FcCacheDir (cache), cache->mtime, (int) dir_stat->st_mtime); - return cache->mtime == (int) dir_stat->st_mtime; + printf ("FcCacheTimeValid dir \"%s\" cache checksum %d dir checksum %d\n", + FcCacheDir (cache), cache->checksum, (int) dir_stat->st_mtime); + return cache->checksum == (int) dir_stat->st_mtime; } /* @@ -815,7 +679,7 @@ FcDirCacheValidateHelper (int fd, struct stat *fd_stat, struct stat *dir_stat, v ret = FcFalse; else if (fd_stat->st_size != c.size) ret = FcFalse; - else if (c.mtime != (int) dir_stat->st_mtime) + else if (c.checksum != (int) dir_stat->st_mtime) ret = FcFalse; return ret; } @@ -890,7 +754,7 @@ FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcSt cache->magic = FC_CACHE_MAGIC_ALLOC; cache->version = FC_CACHE_CONTENT_VERSION; cache->size = serialize->size; - cache->mtime = (int) dir_stat->st_mtime; + cache->checksum = (int) dir_stat->st_mtime; /* * Serialize directory name diff --git a/fontconfig/src/fcdir.c b/fontconfig/src/fcdir.c index 4399afc4a..2b476e8b9 100644 --- a/fontconfig/src/fcdir.c +++ b/fontconfig/src/fcdir.c @@ -245,7 +245,7 @@ FcDirCacheScan (const FcChar8 *dir, FcConfig *config) if (FcDebug () & FC_DBG_FONTSET) printf ("cache scan dir %s\n", dir); - if (FcStat (dir, &dir_stat) < 0) + if (FcStatChecksum (dir, &dir_stat) < 0) goto bail; set = FcFontSetCreate(); diff --git a/fontconfig/src/fcint.h b/fontconfig/src/fcint.h index ad9db8aa4..3d06fc6eb 100644 --- a/fontconfig/src/fcint.h +++ b/fontconfig/src/fcint.h @@ -358,7 +358,7 @@ struct _FcCache { intptr_t dirs; /* offset to subdirs */ int dirs_count; /* number of subdir strings */ intptr_t set; /* offset to font set */ - int mtime; /* low bits of directory mtime */ + int checksum; /* checksum of directory state */ }; #undef FcCacheDir @@ -539,6 +539,13 @@ struct _FcRange { FcChar32 end; }; +typedef struct _FcStatFS FcStatFS; + +struct _FcStatFS { + FcBool is_remote_fs; + FcBool is_mtime_broken; +}; + /* fcblanks.c */ /* fccache.c */ @@ -567,9 +574,6 @@ FcCacheFini (void); FcPrivate void FcDirCacheReference (FcCache *cache, int nref); -FcPrivate int -FcStat (const FcChar8 *file, struct stat *statb); - /* fccfg.c */ FcPrivate FcChar8 * @@ -1020,6 +1024,20 @@ extern FcPrivate const FcMatrix FcIdentityMatrix; FcPrivate void FcMatrixFree (FcMatrix *mat); +/* fcstat.c */ + +FcPrivate int +FcStat (const FcChar8 *file, struct stat *statb); + +FcPrivate int +FcStatChecksum (const FcChar8 *file, struct stat *statb); + +FcPrivate FcBool +FcIsFsMmapSafe (int fd); + +FcPrivate FcBool +FcIsFsMtimeBroken (const FcChar8 *dir); + /* fcstr.c */ FcPrivate void FcStrSetSort (FcStrSet * set); diff --git a/fontconfig/src/fcstat.c b/fontconfig/src/fcstat.c new file mode 100644 index 000000000..c2d9fe9ee --- /dev/null +++ b/fontconfig/src/fcstat.c @@ -0,0 +1,308 @@ +/* + * Copyright © 2000 Keith Packard + * Copyright © 2005 Patrick Lam + * + * 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 + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "fcint.h" +#include "fcarch.h" +#include <dirent.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#ifdef HAVE_SYS_VFS_H +#include <sys/vfs.h> +#endif +#ifdef HAVE_SYS_STATFS_H +#include <sys/statfs.h> +#endif +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif +#ifdef HAVE_SYS_MOUNT_H +#include <sys/mount.h> +#endif + +#ifdef _WIN32 + +#include <windows.h> + +#ifdef __GNUC__ +typedef long long INT64; +#define EPOCH_OFFSET 11644473600ll +#else +#define EPOCH_OFFSET 11644473600i64 +typedef __int64 INT64; +#endif + +/* Workaround for problems in the stat() in the Microsoft C library: + * + * 1) stat() uses FindFirstFile() to get the file + * attributes. Unfortunately this API doesn't return correct values + * for modification time of a directory until some time after a file + * or subdirectory has been added to the directory. (This causes + * run-test.sh to fail, for instance.) GetFileAttributesEx() is + * better, it returns the updated timestamp right away. + * + * 2) stat() does some strange things related to backward + * compatibility with the local time timestamps on FAT volumes and + * daylight saving time. This causes problems after the switches + * to/from daylight saving time. See + * http://bugzilla.gnome.org/show_bug.cgi?id=154968 , especially + * comment #30, and http://www.codeproject.com/datetime/dstbugs.asp . + * We don't need any of that, FAT and Win9x are as good as dead. So + * just use the UTC timestamps from NTFS, converted to the Unix epoch. + */ + +int +FcStat (const FcChar8 *file, struct stat *statb) +{ + WIN32_FILE_ATTRIBUTE_DATA wfad; + char full_path_name[MAX_PATH]; + char *basename; + DWORD rc; + + if (!GetFileAttributesEx (file, GetFileExInfoStandard, &wfad)) + return -1; + + statb->st_dev = 0; + + /* Calculate a pseudo inode number as a hash of the full path name. + * Call GetLongPathName() to get the spelling of the path name as it + * is on disk. + */ + rc = GetFullPathName (file, sizeof (full_path_name), full_path_name, &basename); + if (rc == 0 || rc > sizeof (full_path_name)) + return -1; + + rc = GetLongPathName (full_path_name, full_path_name, sizeof (full_path_name)); + statb->st_ino = FcStringHash (full_path_name); + + statb->st_mode = _S_IREAD | _S_IWRITE; + statb->st_mode |= (statb->st_mode >> 3) | (statb->st_mode >> 6); + + if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + statb->st_mode |= _S_IFDIR; + else + statb->st_mode |= _S_IFREG; + + statb->st_nlink = 1; + statb->st_uid = statb->st_gid = 0; + statb->st_rdev = 0; + + if (wfad.nFileSizeHigh > 0) + return -1; + statb->st_size = wfad.nFileSizeLow; + + statb->st_atime = (*(INT64 *)&wfad.ftLastAccessTime)/10000000 - EPOCH_OFFSET; + statb->st_mtime = (*(INT64 *)&wfad.ftLastWriteTime)/10000000 - EPOCH_OFFSET; + statb->st_ctime = statb->st_mtime; + + return 0; +} + +#else + +int +FcStat (const FcChar8 *file, struct stat *statb) +{ + return stat ((char *) file, statb); +} + +#endif + +/* Adler-32 checksum implementation */ +struct Adler32 { + int a; + int b; +}; + +static void +Adler32Init (struct Adler32 *ctx) +{ + ctx->a = 1; + ctx->b = 0; +} + +static void +Adler32Update (struct Adler32 *ctx, const char *data, int data_len) +{ + while (data_len--) + { + ctx->a = (ctx->a + *data++) % 65521; + ctx->b = (ctx->b + ctx->a) % 65521; + } +} + +static int +Adler32Finish (struct Adler32 *ctx) +{ + return ctx->a + (ctx->b << 16); +} + +/* dirent.d_type can be relied upon on FAT filesystem */ +static FcBool +FcDirChecksumScandirFilter(const struct dirent *entry) +{ + return entry->d_type != DT_DIR; +} + +static int +FcDirChecksumScandirSorter(const struct dirent **lhs, const struct dirent **rhs) +{ + return strcmp((*lhs)->d_name, (*rhs)->d_name); +} + +static int +FcDirChecksum (const FcChar8 *dir, time_t *checksum) +{ + struct Adler32 ctx; + struct dirent **files; + int n; + + Adler32Init (&ctx); + + n = scandir ((const char *)dir, &files, + &FcDirChecksumScandirFilter, + &FcDirChecksumScandirSorter); + if (n == -1) + return -1; + + while (n--) + { + Adler32Update (&ctx, files[n]->d_name, strlen(files[n]->d_name) + 1); + Adler32Update (&ctx, (char *)&files[n]->d_type, sizeof(files[n]->d_type)); + free(files[n]); + } + free(files); + + *checksum = Adler32Finish (&ctx); + return 0; +} + +int +FcStatChecksum (const FcChar8 *file, struct stat *statb) +{ + if (FcStat (file, statb) == -1) + return -1; + + if (FcIsFsMtimeBroken (file)) + { + if (FcDirChecksum (file, &statb->st_mtime) == -1) + return -1; + } + + return 0; +} + +static int +FcFStatFs (int fd, FcStatFS *statb) +{ + const char *p = NULL; + int ret; + FcBool flag = FcFalse; + + memset (statb, 0, sizeof (FcStatFS)); + +#if defined(HAVE_FSTATVFS) && (defined(HAVE_STRUCT_STATVFS_F_BASETYPE) || defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME)) + struct statvfs buf; + + if ((ret = fstatvfs (fd, &buf)) == 0) + { +# if defined(HAVE_STRUCT_STATVFS_F_BASETYPE) + p = buf.f_basetype; +# elif defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME) + p = buf.f_fstypename; +# endif + } +#elif defined(HAVE_FSTATFS) && (defined(HAVE_STRUCT_STATFS_F_FLAGS) || defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) || defined(__linux__)) + struct statfs buf; + + if ((ret = fstatfs (fd, &buf)) == 0) + { +# if defined(HAVE_STRUCT_STATFS_F_FLAGS) && defined(MNT_LOCAL) + statb->is_remote_fs = !(buf.f_flags & MNT_LOCAL); + flag = FcTrue; +# endif +# if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) + p = buf.f_fstypename; +# elif defined(__linux__) + switch (buf.f_type) + { + case 0x6969: /* nfs */ + statb->is_remote_fs = FcTrue; + break; + case 0x4d44: /* fat */ + statb->is_mtime_broken = FcTrue; + break; + default: + break; + } + + return ret; +# else +# error "BUG: No way to figure out with fstatfs()" +# endif + } +#endif + if (p) + { + if (!flag && strcmp (p, "nfs") == 0) + statb->is_remote_fs = FcTrue; + if (strcmp (p, "msdosfs") == 0 || + strcmp (p, "pcfs") == 0) + statb->is_mtime_broken = FcTrue; + } + + return ret; +} + +FcBool +FcIsFsMmapSafe (int fd) +{ + FcStatFS statb; + + if (FcFStatFs (fd, &statb) < 0) + return FcTrue; + + return !statb.is_remote_fs; +} + +FcBool +FcIsFsMtimeBroken (const FcChar8 *dir) +{ + int fd = open ((const char *) dir, O_RDONLY); + + if (fd != -1) + { + FcStatFS statb; + int ret = FcFStatFs (fd, &statb); + + close (fd); + if (ret < 0) + return FcFalse; + + return statb.is_mtime_broken; + } + + return FcFalse; +} |