2 * Copyright © 2000 Keith Packard
3 * Copyright © 2005 Patrick Lam
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the author(s) not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission. The authors make no
12 * representations about the suitability of this software for any purpose. It
13 * is provided "as is" without express or implied warranty.
15 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
27 #include <sys/types.h>
33 #ifdef HAVE_SYS_STATVFS_H
34 #include <sys/statvfs.h>
36 #ifdef HAVE_SYS_STATFS_H
37 #include <sys/statfs.h>
39 #ifdef HAVE_SYS_PARAM_H
40 #include <sys/param.h>
42 #ifdef HAVE_SYS_MOUNT_H
43 #include <sys/mount.h>
49 typedef long long INT64;
50 #define EPOCH_OFFSET 11644473600ll
52 #define EPOCH_OFFSET 11644473600i64
53 typedef __int64 INT64;
56 /* Workaround for problems in the stat() in the Microsoft C library:
58 * 1) stat() uses FindFirstFile() to get the file
59 * attributes. Unfortunately this API doesn't return correct values
60 * for modification time of a directory until some time after a file
61 * or subdirectory has been added to the directory. (This causes
62 * run-test.sh to fail, for instance.) GetFileAttributesEx() is
63 * better, it returns the updated timestamp right away.
65 * 2) stat() does some strange things related to backward
66 * compatibility with the local time timestamps on FAT volumes and
67 * daylight saving time. This causes problems after the switches
68 * to/from daylight saving time. See
69 * http://bugzilla.gnome.org/show_bug.cgi?id=154968 , especially
70 * comment #30, and http://www.codeproject.com/datetime/dstbugs.asp .
71 * We don't need any of that, FAT and Win9x are as good as dead. So
72 * just use the UTC timestamps from NTFS, converted to the Unix epoch.
76 FcStat (const FcChar8 *file, struct stat *statb)
78 WIN32_FILE_ATTRIBUTE_DATA wfad;
79 char full_path_name[MAX_PATH];
83 if (!GetFileAttributesEx ((LPCSTR) file, GetFileExInfoStandard, &wfad))
88 /* Calculate a pseudo inode number as a hash of the full path name.
89 * Call GetLongPathName() to get the spelling of the path name as it
92 rc = GetFullPathName ((LPCSTR) file, sizeof (full_path_name), full_path_name, &basename);
93 if (rc == 0 || rc > sizeof (full_path_name))
96 rc = GetLongPathName (full_path_name, full_path_name, sizeof (full_path_name));
97 statb->st_ino = FcStringHash ((const FcChar8 *) full_path_name);
99 statb->st_mode = _S_IREAD | _S_IWRITE;
100 statb->st_mode |= (statb->st_mode >> 3) | (statb->st_mode >> 6);
102 if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
103 statb->st_mode |= _S_IFDIR;
105 statb->st_mode |= _S_IFREG;
108 statb->st_uid = statb->st_gid = 0;
111 if (wfad.nFileSizeHigh > 0)
113 statb->st_size = wfad.nFileSizeLow;
115 statb->st_atime = (*(INT64 *)&wfad.ftLastAccessTime)/10000000 - EPOCH_OFFSET;
116 statb->st_mtime = (*(INT64 *)&wfad.ftLastWriteTime)/10000000 - EPOCH_OFFSET;
117 statb->st_ctime = statb->st_mtime;
125 FcStat (const FcChar8 *file, struct stat *statb)
127 return stat ((char *) file, statb);
130 /* Adler-32 checksum implementation */
137 Adler32Init (struct Adler32 *ctx)
144 Adler32Update (struct Adler32 *ctx, const char *data, int data_len)
148 ctx->a = (ctx->a + *data++) % 65521;
149 ctx->b = (ctx->b + ctx->a) % 65521;
154 Adler32Finish (struct Adler32 *ctx)
156 return ctx->a + (ctx->b << 16);
159 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
160 /* dirent.d_type can be relied upon on FAT filesystem */
162 FcDirChecksumScandirFilter(const struct dirent *entry)
164 return entry->d_type != DT_DIR;
169 FcDirChecksumScandirSorter(const struct dirent **lhs, const struct dirent **rhs)
171 return strcmp((*lhs)->d_name, (*rhs)->d_name);
175 free_dirent (struct dirent **p)
179 for (x = p; *x != NULL; x++)
186 FcScandir (const char *dirp,
187 struct dirent ***namelist,
188 int (*filter) (const struct dirent *),
189 int (*compar) (const struct dirent **, const struct dirent **));
192 FcScandir (const char *dirp,
193 struct dirent ***namelist,
194 int (*filter) (const struct dirent *),
195 int (*compar) (const struct dirent **, const struct dirent **))
198 struct dirent *dent, *p, **dlist, **dlp;
199 size_t lsize = 128, n = 0;
205 dlist = (struct dirent **) malloc (sizeof (struct dirent *) * lsize);
214 while ((dent = readdir (d)))
216 if (!filter || (filter) (dent))
218 size_t dentlen = FcPtrToOffset (dent, dent->d_name) + strlen (dent->d_name) + 1;
219 dentlen = ((dentlen + ALIGNOF_VOID_P - 1) & ~(ALIGNOF_VOID_P - 1));
220 p = (struct dirent *) malloc (dentlen);
221 memcpy (p, dent, dentlen);
222 if ((n + 1) >= lsize)
225 dlp = (struct dirent **) realloc (dlist, sizeof (struct dirent *) * lsize);
242 qsort (dlist, n, sizeof (struct dirent *), (int (*) (const void *, const void *))compar);
250 FcDirChecksum (const FcChar8 *dir, time_t *checksum)
253 struct dirent **files;
256 size_t len = strlen ((const char *)dir);
260 n = FcScandir ((const char *)dir, &files,
261 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
262 &FcDirChecksumScandirFilter,
266 &FcDirChecksumScandirSorter);
272 size_t dlen = strlen (files[n]->d_name);
275 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
276 dtype = files[n]->d_type;
277 if (dtype == DT_UNKNOWN)
281 char *f = malloc (len + 1 + dlen + 1);
288 memcpy (f, dir, len);
289 f[len] = FC_DIR_SEPARATOR;
290 memcpy (&f[len + 1], files[n]->d_name, dlen);
291 f[len + 1 + dlen] = 0;
292 if (lstat (f, &statb) < 0)
298 if (S_ISDIR (statb.st_mode))
305 dtype = statb.st_mode;
306 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
309 Adler32Update (&ctx, files[n]->d_name, dlen + 1);
310 Adler32Update (&ctx, (char *)&dtype, sizeof (int));
319 *checksum = Adler32Finish (&ctx);
326 FcStatChecksum (const FcChar8 *file, struct stat *statb)
328 if (FcStat (file, statb) == -1)
332 /* We have a workaround of the broken stat() in FcStat() for Win32.
333 * No need to do something further more.
335 if (FcIsFsMtimeBroken (file))
337 if (FcDirChecksum (file, &statb->st_mtime) == -1)
346 FcFStatFs (int fd, FcStatFS *statb)
348 const char *p = NULL;
350 FcBool flag = FcFalse;
352 #if defined(HAVE_FSTATVFS) && (defined(HAVE_STRUCT_STATVFS_F_BASETYPE) || defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME))
355 memset (statb, 0, sizeof (FcStatFS));
357 if ((ret = fstatvfs (fd, &buf)) == 0)
359 # if defined(HAVE_STRUCT_STATVFS_F_BASETYPE)
361 # elif defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME)
362 p = buf.f_fstypename;
365 #elif defined(HAVE_FSTATFS) && (defined(HAVE_STRUCT_STATFS_F_FLAGS) || defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) || defined(__linux__))
368 memset (statb, 0, sizeof (FcStatFS));
370 if ((ret = fstatfs (fd, &buf)) == 0)
372 # if defined(HAVE_STRUCT_STATFS_F_FLAGS) && defined(MNT_LOCAL)
373 statb->is_remote_fs = !(buf.f_flags & MNT_LOCAL);
376 # if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME)
377 p = buf.f_fstypename;
378 # elif defined(__linux__)
381 case 0x6969: /* nfs */
382 statb->is_remote_fs = FcTrue;
384 case 0x4d44: /* fat */
385 statb->is_mtime_broken = FcTrue;
393 # error "BUG: No way to figure out with fstatfs()"
399 if (!flag && strcmp (p, "nfs") == 0)
400 statb->is_remote_fs = FcTrue;
401 if (strcmp (p, "msdosfs") == 0 ||
402 strcmp (p, "pcfs") == 0)
403 statb->is_mtime_broken = FcTrue;
410 FcIsFsMmapSafe (int fd)
414 if (FcFStatFs (fd, &statb) < 0)
417 return !statb.is_remote_fs;
421 FcIsFsMtimeBroken (const FcChar8 *dir)
423 int fd = FcOpen ((const char *) dir, O_RDONLY);
428 int ret = FcFStatFs (fd, &statb);
434 return statb.is_mtime_broken;
441 #include "fcaliastail.h"