12c393a42Smrg/* 2a6844aabSmrg * fontconfig/src/fcatomic.c 32c393a42Smrg * 42c393a42Smrg * Copyright © 2002 Keith Packard 52c393a42Smrg * 62c393a42Smrg * Permission to use, copy, modify, distribute, and sell this software and its 72c393a42Smrg * documentation for any purpose is hereby granted without fee, provided that 82c393a42Smrg * the above copyright notice appear in all copies and that both that 92c393a42Smrg * copyright notice and this permission notice appear in supporting 10ca08ab68Smrg * documentation, and that the name of the author(s) not be used in 112c393a42Smrg * advertising or publicity pertaining to distribution of the software without 12ca08ab68Smrg * specific, written prior permission. The authors make no 132c393a42Smrg * representations about the suitability of this software for any purpose. It 142c393a42Smrg * is provided "as is" without express or implied warranty. 152c393a42Smrg * 16a6844aabSmrg * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18a6844aabSmrg * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 192c393a42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 202c393a42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 212c393a42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 222c393a42Smrg * PERFORMANCE OF THIS SOFTWARE. 232c393a42Smrg */ 242c393a42Smrg 252c393a42Smrg/* 262c393a42Smrg * fcatomic.c 272c393a42Smrg * 282c393a42Smrg * Lock cache and configuration files for atomic update 292c393a42Smrg * 302c393a42Smrg * Uses only regular filesystem calls so it should 312c393a42Smrg * work even in the absense of functioning file locking 322c393a42Smrg * 332c393a42Smrg * On Unix, four files are used: 342c393a42Smrg * file - the data file accessed by other apps. 352c393a42Smrg * new - a new version of the data file while it's being written 362c393a42Smrg * lck - the lock file 372c393a42Smrg * tmp - a temporary file made unique with mkstemp 382c393a42Smrg * 392c393a42Smrg * Here's how it works: 402c393a42Smrg * Create 'tmp' and store our PID in it 412c393a42Smrg * Attempt to link it to 'lck' 422c393a42Smrg * Unlink 'tmp' 432c393a42Smrg * If the link succeeded, the lock is held 442c393a42Smrg * 452c393a42Smrg * On Windows, where there are no links, no tmp file is used, and lck 462c393a42Smrg * is a directory that's mkdir'ed. If the mkdir succeeds, the lock is 472c393a42Smrg * held. 482c393a42Smrg */ 492c393a42Smrg 50a4e54154Smrg#ifdef HAVE_CONFIG_H 51a4e54154Smrg#include <config.h> 52a4e54154Smrg#endif 53a4e54154Smrg 542c393a42Smrg#include "fcint.h" 552c393a42Smrg#include <sys/types.h> 562c393a42Smrg#include <sys/stat.h> 572c393a42Smrg#include <stdlib.h> 582c393a42Smrg#include <time.h> 592c393a42Smrg 60a4e54154Smrg#ifdef HAVE_UNISTD_H 61a4e54154Smrg#include <unistd.h> 62a4e54154Smrg#endif 63a4e54154Smrg 642c393a42Smrg#ifdef _WIN32 65c9710b42Smrg#include <direct.h> 662c393a42Smrg#define mkdir(path,mode) _mkdir(path) 672c393a42Smrg#endif 682c393a42Smrg 692c393a42Smrg#define NEW_NAME ".NEW" 702c393a42Smrg#define LCK_NAME ".LCK" 712c393a42Smrg#define TMP_NAME ".TMP-XXXXXX" 722c393a42Smrg 732c393a42SmrgFcAtomic * 742c393a42SmrgFcAtomicCreate (const FcChar8 *file) 752c393a42Smrg{ 762c393a42Smrg int file_len = strlen ((char *) file); 772c393a42Smrg int new_len = file_len + sizeof (NEW_NAME); 782c393a42Smrg int lck_len = file_len + sizeof (LCK_NAME); 792c393a42Smrg int tmp_len = file_len + sizeof (TMP_NAME); 802c393a42Smrg int total_len = (sizeof (FcAtomic) + 812c393a42Smrg file_len + 1 + 822c393a42Smrg new_len + 1 + 832c393a42Smrg lck_len + 1 + 842c393a42Smrg tmp_len + 1); 852c393a42Smrg FcAtomic *atomic = malloc (total_len); 862c393a42Smrg if (!atomic) 872c393a42Smrg return 0; 88ca08ab68Smrg 892c393a42Smrg atomic->file = (FcChar8 *) (atomic + 1); 902c393a42Smrg strcpy ((char *) atomic->file, (char *) file); 912c393a42Smrg 922c393a42Smrg atomic->new = atomic->file + file_len + 1; 932c393a42Smrg strcpy ((char *) atomic->new, (char *) file); 942c393a42Smrg strcat ((char *) atomic->new, NEW_NAME); 952c393a42Smrg 962c393a42Smrg atomic->lck = atomic->new + new_len + 1; 972c393a42Smrg strcpy ((char *) atomic->lck, (char *) file); 982c393a42Smrg strcat ((char *) atomic->lck, LCK_NAME); 992c393a42Smrg 1002c393a42Smrg atomic->tmp = atomic->lck + lck_len + 1; 1012c393a42Smrg 1022c393a42Smrg return atomic; 1032c393a42Smrg} 1042c393a42Smrg 1052c393a42SmrgFcBool 1062c393a42SmrgFcAtomicLock (FcAtomic *atomic) 1072c393a42Smrg{ 1082c393a42Smrg int ret; 1092c393a42Smrg struct stat lck_stat; 1102c393a42Smrg 1112c393a42Smrg#ifdef HAVE_LINK 112ca08ab68Smrg int fd = -1; 113ca08ab68Smrg FILE *f = 0; 114ca08ab68Smrg FcBool no_link = FcFalse; 115ca08ab68Smrg 1162c393a42Smrg strcpy ((char *) atomic->tmp, (char *) atomic->file); 1172c393a42Smrg strcat ((char *) atomic->tmp, TMP_NAME); 118c9710b42Smrg fd = FcMakeTempfile ((char *) atomic->tmp); 1192c393a42Smrg if (fd < 0) 1202c393a42Smrg return FcFalse; 1212c393a42Smrg f = fdopen (fd, "w"); 1222c393a42Smrg if (!f) 1232c393a42Smrg { 1242c393a42Smrg close (fd); 1252c393a42Smrg unlink ((char *) atomic->tmp); 1262c393a42Smrg return FcFalse; 1272c393a42Smrg } 1282c393a42Smrg ret = fprintf (f, "%ld\n", (long)getpid()); 1292c393a42Smrg if (ret <= 0) 1302c393a42Smrg { 1312c393a42Smrg fclose (f); 1322c393a42Smrg unlink ((char *) atomic->tmp); 1332c393a42Smrg return FcFalse; 1342c393a42Smrg } 1352c393a42Smrg if (fclose (f) == EOF) 1362c393a42Smrg { 1372c393a42Smrg unlink ((char *) atomic->tmp); 1382c393a42Smrg return FcFalse; 1392c393a42Smrg } 1402c393a42Smrg ret = link ((char *) atomic->tmp, (char *) atomic->lck); 141953daebaSmrg if (ret < 0 && (errno == EPERM || errno == ENOTSUP || errno == EACCES)) 142ca08ab68Smrg { 143ca08ab68Smrg /* the filesystem where atomic->lck points to may not supports 144ca08ab68Smrg * the hard link. so better try to fallback 145ca08ab68Smrg */ 146ca08ab68Smrg ret = mkdir ((char *) atomic->lck, 0600); 147ca08ab68Smrg no_link = FcTrue; 148ca08ab68Smrg } 1492c393a42Smrg (void) unlink ((char *) atomic->tmp); 1502c393a42Smrg#else 1512c393a42Smrg ret = mkdir ((char *) atomic->lck, 0600); 1522c393a42Smrg#endif 1532c393a42Smrg if (ret < 0) 1542c393a42Smrg { 1552c393a42Smrg /* 1562c393a42Smrg * If the file is around and old (> 10 minutes), 1572c393a42Smrg * assume the lock is stale. This assumes that any 1582c393a42Smrg * machines sharing the same filesystem will have clocks 1592c393a42Smrg * reasonably close to each other. 1602c393a42Smrg */ 161ca08ab68Smrg if (FcStat (atomic->lck, &lck_stat) >= 0) 1622c393a42Smrg { 1632c393a42Smrg time_t now = time (0); 1642c393a42Smrg if ((long int) (now - lck_stat.st_mtime) > 10 * 60) 1652c393a42Smrg { 1662c393a42Smrg#ifdef HAVE_LINK 167ca08ab68Smrg if (no_link) 168ca08ab68Smrg { 169ca08ab68Smrg if (rmdir ((char *) atomic->lck) == 0) 170ca08ab68Smrg return FcAtomicLock (atomic); 171ca08ab68Smrg } 172ca08ab68Smrg else 173ca08ab68Smrg { 174ca08ab68Smrg if (unlink ((char *) atomic->lck) == 0) 175ca08ab68Smrg return FcAtomicLock (atomic); 176ca08ab68Smrg } 1772c393a42Smrg#else 1782c393a42Smrg if (rmdir ((char *) atomic->lck) == 0) 1792c393a42Smrg return FcAtomicLock (atomic); 1802c393a42Smrg#endif 1812c393a42Smrg } 1822c393a42Smrg } 1832c393a42Smrg return FcFalse; 1842c393a42Smrg } 1852c393a42Smrg (void) unlink ((char *) atomic->new); 1862c393a42Smrg return FcTrue; 1872c393a42Smrg} 1882c393a42Smrg 1892c393a42SmrgFcChar8 * 1902c393a42SmrgFcAtomicNewFile (FcAtomic *atomic) 1912c393a42Smrg{ 1922c393a42Smrg return atomic->new; 1932c393a42Smrg} 1942c393a42Smrg 1952c393a42SmrgFcChar8 * 1962c393a42SmrgFcAtomicOrigFile (FcAtomic *atomic) 1972c393a42Smrg{ 1982c393a42Smrg return atomic->file; 1992c393a42Smrg} 2002c393a42Smrg 2012c393a42SmrgFcBool 2022c393a42SmrgFcAtomicReplaceOrig (FcAtomic *atomic) 2032c393a42Smrg{ 2042c393a42Smrg#ifdef _WIN32 205ca08ab68Smrg unlink ((const char *) atomic->file); 2062c393a42Smrg#endif 2072c393a42Smrg if (rename ((char *) atomic->new, (char *) atomic->file) < 0) 2082c393a42Smrg return FcFalse; 2092c393a42Smrg return FcTrue; 2102c393a42Smrg} 2112c393a42Smrg 2122c393a42Smrgvoid 2132c393a42SmrgFcAtomicDeleteNew (FcAtomic *atomic) 2142c393a42Smrg{ 2152c393a42Smrg unlink ((char *) atomic->new); 2162c393a42Smrg} 2172c393a42Smrg 2182c393a42Smrgvoid 2192c393a42SmrgFcAtomicUnlock (FcAtomic *atomic) 2202c393a42Smrg{ 2212c393a42Smrg#ifdef HAVE_LINK 222ca08ab68Smrg if (unlink ((char *) atomic->lck) == -1) 223ca08ab68Smrg rmdir ((char *) atomic->lck); 2242c393a42Smrg#else 2252c393a42Smrg rmdir ((char *) atomic->lck); 2262c393a42Smrg#endif 2272c393a42Smrg} 2282c393a42Smrg 2292c393a42Smrgvoid 2302c393a42SmrgFcAtomicDestroy (FcAtomic *atomic) 2312c393a42Smrg{ 2321cc69409Smrg if (atomic) 2331cc69409Smrg free (atomic); 2342c393a42Smrg} 2352c393a42Smrg#define __fcatomic__ 2362c393a42Smrg#include "fcaliastail.h" 2372c393a42Smrg#undef __fcatomic__ 238