fontconfig/src/fcstat.c

225 lines
5.9 KiB
C
Raw Normal View History

/*
* 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
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;
}