fcatomic.c revision 2c393a42
12c393a42Smrg/* 22c393a42Smrg * $RCSId: xc/lib/fontconfig/src/fcatomic.c,v 1.2 2002/03/04 21:15:28 tsi Exp $ 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 102c393a42Smrg * documentation, and that the name of Keith Packard not be used in 112c393a42Smrg * advertising or publicity pertaining to distribution of the software without 122c393a42Smrg * specific, written prior permission. Keith Packard makes no 132c393a42Smrg * representations about the suitability of this software for any purpose. It 142c393a42Smrg * is provided "as is" without express or implied warranty. 152c393a42Smrg * 162c393a42Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 182c393a42Smrg * EVENT SHALL KEITH PACKARD 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 502c393a42Smrg#include "fcint.h" 512c393a42Smrg#include <sys/types.h> 522c393a42Smrg#include <sys/stat.h> 532c393a42Smrg#include <fcntl.h> 542c393a42Smrg#include <unistd.h> 552c393a42Smrg#include <stdlib.h> 562c393a42Smrg#include <time.h> 572c393a42Smrg 582c393a42Smrg#ifdef _WIN32 592c393a42Smrg#define mkdir(path,mode) _mkdir(path) 602c393a42Smrg#endif 612c393a42Smrg 622c393a42Smrg#define NEW_NAME ".NEW" 632c393a42Smrg#define LCK_NAME ".LCK" 642c393a42Smrg#define TMP_NAME ".TMP-XXXXXX" 652c393a42Smrg 662c393a42SmrgFcAtomic * 672c393a42SmrgFcAtomicCreate (const FcChar8 *file) 682c393a42Smrg{ 692c393a42Smrg int file_len = strlen ((char *) file); 702c393a42Smrg int new_len = file_len + sizeof (NEW_NAME); 712c393a42Smrg int lck_len = file_len + sizeof (LCK_NAME); 722c393a42Smrg int tmp_len = file_len + sizeof (TMP_NAME); 732c393a42Smrg int total_len = (sizeof (FcAtomic) + 742c393a42Smrg file_len + 1 + 752c393a42Smrg new_len + 1 + 762c393a42Smrg lck_len + 1 + 772c393a42Smrg tmp_len + 1); 782c393a42Smrg FcAtomic *atomic = malloc (total_len); 792c393a42Smrg if (!atomic) 802c393a42Smrg return 0; 812c393a42Smrg FcMemAlloc (FC_MEM_ATOMIC, total_len); 822c393a42Smrg 832c393a42Smrg atomic->file = (FcChar8 *) (atomic + 1); 842c393a42Smrg strcpy ((char *) atomic->file, (char *) file); 852c393a42Smrg 862c393a42Smrg atomic->new = atomic->file + file_len + 1; 872c393a42Smrg strcpy ((char *) atomic->new, (char *) file); 882c393a42Smrg strcat ((char *) atomic->new, NEW_NAME); 892c393a42Smrg 902c393a42Smrg atomic->lck = atomic->new + new_len + 1; 912c393a42Smrg strcpy ((char *) atomic->lck, (char *) file); 922c393a42Smrg strcat ((char *) atomic->lck, LCK_NAME); 932c393a42Smrg 942c393a42Smrg atomic->tmp = atomic->lck + lck_len + 1; 952c393a42Smrg 962c393a42Smrg return atomic; 972c393a42Smrg} 982c393a42Smrg 992c393a42SmrgFcBool 1002c393a42SmrgFcAtomicLock (FcAtomic *atomic) 1012c393a42Smrg{ 1022c393a42Smrg int fd = -1; 1032c393a42Smrg FILE *f = 0; 1042c393a42Smrg int ret; 1052c393a42Smrg struct stat lck_stat; 1062c393a42Smrg 1072c393a42Smrg#ifdef HAVE_LINK 1082c393a42Smrg strcpy ((char *) atomic->tmp, (char *) atomic->file); 1092c393a42Smrg strcat ((char *) atomic->tmp, TMP_NAME); 1102c393a42Smrg fd = mkstemp ((char *) atomic->tmp); 1112c393a42Smrg if (fd < 0) 1122c393a42Smrg return FcFalse; 1132c393a42Smrg f = fdopen (fd, "w"); 1142c393a42Smrg if (!f) 1152c393a42Smrg { 1162c393a42Smrg close (fd); 1172c393a42Smrg unlink ((char *) atomic->tmp); 1182c393a42Smrg return FcFalse; 1192c393a42Smrg } 1202c393a42Smrg ret = fprintf (f, "%ld\n", (long)getpid()); 1212c393a42Smrg if (ret <= 0) 1222c393a42Smrg { 1232c393a42Smrg fclose (f); 1242c393a42Smrg unlink ((char *) atomic->tmp); 1252c393a42Smrg return FcFalse; 1262c393a42Smrg } 1272c393a42Smrg if (fclose (f) == EOF) 1282c393a42Smrg { 1292c393a42Smrg unlink ((char *) atomic->tmp); 1302c393a42Smrg return FcFalse; 1312c393a42Smrg } 1322c393a42Smrg ret = link ((char *) atomic->tmp, (char *) atomic->lck); 1332c393a42Smrg (void) unlink ((char *) atomic->tmp); 1342c393a42Smrg#else 1352c393a42Smrg ret = mkdir ((char *) atomic->lck, 0600); 1362c393a42Smrg#endif 1372c393a42Smrg if (ret < 0) 1382c393a42Smrg { 1392c393a42Smrg /* 1402c393a42Smrg * If the file is around and old (> 10 minutes), 1412c393a42Smrg * assume the lock is stale. This assumes that any 1422c393a42Smrg * machines sharing the same filesystem will have clocks 1432c393a42Smrg * reasonably close to each other. 1442c393a42Smrg */ 1452c393a42Smrg if (stat ((char *) atomic->lck, &lck_stat) >= 0) 1462c393a42Smrg { 1472c393a42Smrg time_t now = time (0); 1482c393a42Smrg if ((long int) (now - lck_stat.st_mtime) > 10 * 60) 1492c393a42Smrg { 1502c393a42Smrg#ifdef HAVE_LINK 1512c393a42Smrg if (unlink ((char *) atomic->lck) == 0) 1522c393a42Smrg return FcAtomicLock (atomic); 1532c393a42Smrg#else 1542c393a42Smrg if (rmdir ((char *) atomic->lck) == 0) 1552c393a42Smrg return FcAtomicLock (atomic); 1562c393a42Smrg#endif 1572c393a42Smrg } 1582c393a42Smrg } 1592c393a42Smrg return FcFalse; 1602c393a42Smrg } 1612c393a42Smrg (void) unlink ((char *) atomic->new); 1622c393a42Smrg return FcTrue; 1632c393a42Smrg} 1642c393a42Smrg 1652c393a42SmrgFcChar8 * 1662c393a42SmrgFcAtomicNewFile (FcAtomic *atomic) 1672c393a42Smrg{ 1682c393a42Smrg return atomic->new; 1692c393a42Smrg} 1702c393a42Smrg 1712c393a42SmrgFcChar8 * 1722c393a42SmrgFcAtomicOrigFile (FcAtomic *atomic) 1732c393a42Smrg{ 1742c393a42Smrg return atomic->file; 1752c393a42Smrg} 1762c393a42Smrg 1772c393a42SmrgFcBool 1782c393a42SmrgFcAtomicReplaceOrig (FcAtomic *atomic) 1792c393a42Smrg{ 1802c393a42Smrg#ifdef _WIN32 1812c393a42Smrg unlink (atomic->file); 1822c393a42Smrg#endif 1832c393a42Smrg if (rename ((char *) atomic->new, (char *) atomic->file) < 0) 1842c393a42Smrg return FcFalse; 1852c393a42Smrg return FcTrue; 1862c393a42Smrg} 1872c393a42Smrg 1882c393a42Smrgvoid 1892c393a42SmrgFcAtomicDeleteNew (FcAtomic *atomic) 1902c393a42Smrg{ 1912c393a42Smrg unlink ((char *) atomic->new); 1922c393a42Smrg} 1932c393a42Smrg 1942c393a42Smrgvoid 1952c393a42SmrgFcAtomicUnlock (FcAtomic *atomic) 1962c393a42Smrg{ 1972c393a42Smrg#ifdef HAVE_LINK 1982c393a42Smrg unlink ((char *) atomic->lck); 1992c393a42Smrg#else 2002c393a42Smrg rmdir ((char *) atomic->lck); 2012c393a42Smrg#endif 2022c393a42Smrg} 2032c393a42Smrg 2042c393a42Smrgvoid 2052c393a42SmrgFcAtomicDestroy (FcAtomic *atomic) 2062c393a42Smrg{ 2072c393a42Smrg FcMemFree (FC_MEM_ATOMIC, sizeof (FcAtomic) + 2082c393a42Smrg strlen ((char *) atomic->file) * 4 + 4 + 2092c393a42Smrg sizeof (NEW_NAME) + sizeof (LCK_NAME) + 2102c393a42Smrg sizeof (TMP_NAME)); 2112c393a42Smrg 2122c393a42Smrg free (atomic); 2132c393a42Smrg} 2142c393a42Smrg#define __fcatomic__ 2152c393a42Smrg#include "fcaliastail.h" 2162c393a42Smrg#undef __fcatomic__ 217