fcatomic.c revision a4e54154
1/* 2 * fontconfig/src/fcatomic.c 3 * 4 * Copyright © 2002 Keith Packard 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of the author(s) not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. The authors make no 13 * representations about the suitability of this software for any purpose. It 14 * is provided "as is" without express or implied warranty. 15 * 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25/* 26 * fcatomic.c 27 * 28 * Lock cache and configuration files for atomic update 29 * 30 * Uses only regular filesystem calls so it should 31 * work even in the absense of functioning file locking 32 * 33 * On Unix, four files are used: 34 * file - the data file accessed by other apps. 35 * new - a new version of the data file while it's being written 36 * lck - the lock file 37 * tmp - a temporary file made unique with mkstemp 38 * 39 * Here's how it works: 40 * Create 'tmp' and store our PID in it 41 * Attempt to link it to 'lck' 42 * Unlink 'tmp' 43 * If the link succeeded, the lock is held 44 * 45 * On Windows, where there are no links, no tmp file is used, and lck 46 * is a directory that's mkdir'ed. If the mkdir succeeds, the lock is 47 * held. 48 */ 49 50#ifdef HAVE_CONFIG_H 51#include <config.h> 52#endif 53 54#include "fcint.h" 55#include <sys/types.h> 56#include <sys/stat.h> 57#include <stdlib.h> 58#include <time.h> 59 60#ifdef HAVE_UNISTD_H 61#include <unistd.h> 62#endif 63 64#ifdef _WIN32 65#include <direct.h> 66#define mkdir(path,mode) _mkdir(path) 67#endif 68 69#define NEW_NAME ".NEW" 70#define LCK_NAME ".LCK" 71#define TMP_NAME ".TMP-XXXXXX" 72 73FcAtomic * 74FcAtomicCreate (const FcChar8 *file) 75{ 76 int file_len = strlen ((char *) file); 77 int new_len = file_len + sizeof (NEW_NAME); 78 int lck_len = file_len + sizeof (LCK_NAME); 79 int tmp_len = file_len + sizeof (TMP_NAME); 80 int total_len = (sizeof (FcAtomic) + 81 file_len + 1 + 82 new_len + 1 + 83 lck_len + 1 + 84 tmp_len + 1); 85 FcAtomic *atomic = malloc (total_len); 86 if (!atomic) 87 return 0; 88 89 atomic->file = (FcChar8 *) (atomic + 1); 90 strcpy ((char *) atomic->file, (char *) file); 91 92 atomic->new = atomic->file + file_len + 1; 93 strcpy ((char *) atomic->new, (char *) file); 94 strcat ((char *) atomic->new, NEW_NAME); 95 96 atomic->lck = atomic->new + new_len + 1; 97 strcpy ((char *) atomic->lck, (char *) file); 98 strcat ((char *) atomic->lck, LCK_NAME); 99 100 atomic->tmp = atomic->lck + lck_len + 1; 101 102 return atomic; 103} 104 105FcBool 106FcAtomicLock (FcAtomic *atomic) 107{ 108 int ret; 109 struct stat lck_stat; 110 111#ifdef HAVE_LINK 112 int fd = -1; 113 FILE *f = 0; 114 FcBool no_link = FcFalse; 115 116 strcpy ((char *) atomic->tmp, (char *) atomic->file); 117 strcat ((char *) atomic->tmp, TMP_NAME); 118 fd = FcMakeTempfile ((char *) atomic->tmp); 119 if (fd < 0) 120 return FcFalse; 121 f = fdopen (fd, "w"); 122 if (!f) 123 { 124 close (fd); 125 unlink ((char *) atomic->tmp); 126 return FcFalse; 127 } 128 ret = fprintf (f, "%ld\n", (long)getpid()); 129 if (ret <= 0) 130 { 131 fclose (f); 132 unlink ((char *) atomic->tmp); 133 return FcFalse; 134 } 135 if (fclose (f) == EOF) 136 { 137 unlink ((char *) atomic->tmp); 138 return FcFalse; 139 } 140 ret = link ((char *) atomic->tmp, (char *) atomic->lck); 141 if (ret < 0 && (errno == EPERM || errno == ENOTSUP || errno == EACCES)) 142 { 143 /* the filesystem where atomic->lck points to may not supports 144 * the hard link. so better try to fallback 145 */ 146 ret = mkdir ((char *) atomic->lck, 0600); 147 no_link = FcTrue; 148 } 149 (void) unlink ((char *) atomic->tmp); 150#else 151 ret = mkdir ((char *) atomic->lck, 0600); 152#endif 153 if (ret < 0) 154 { 155 /* 156 * If the file is around and old (> 10 minutes), 157 * assume the lock is stale. This assumes that any 158 * machines sharing the same filesystem will have clocks 159 * reasonably close to each other. 160 */ 161 if (FcStat (atomic->lck, &lck_stat) >= 0) 162 { 163 time_t now = time (0); 164 if ((long int) (now - lck_stat.st_mtime) > 10 * 60) 165 { 166#ifdef HAVE_LINK 167 if (no_link) 168 { 169 if (rmdir ((char *) atomic->lck) == 0) 170 return FcAtomicLock (atomic); 171 } 172 else 173 { 174 if (unlink ((char *) atomic->lck) == 0) 175 return FcAtomicLock (atomic); 176 } 177#else 178 if (rmdir ((char *) atomic->lck) == 0) 179 return FcAtomicLock (atomic); 180#endif 181 } 182 } 183 return FcFalse; 184 } 185 (void) unlink ((char *) atomic->new); 186 return FcTrue; 187} 188 189FcChar8 * 190FcAtomicNewFile (FcAtomic *atomic) 191{ 192 return atomic->new; 193} 194 195FcChar8 * 196FcAtomicOrigFile (FcAtomic *atomic) 197{ 198 return atomic->file; 199} 200 201FcBool 202FcAtomicReplaceOrig (FcAtomic *atomic) 203{ 204#ifdef _WIN32 205 unlink ((const char *) atomic->file); 206#endif 207 if (rename ((char *) atomic->new, (char *) atomic->file) < 0) 208 return FcFalse; 209 return FcTrue; 210} 211 212void 213FcAtomicDeleteNew (FcAtomic *atomic) 214{ 215 unlink ((char *) atomic->new); 216} 217 218void 219FcAtomicUnlock (FcAtomic *atomic) 220{ 221#ifdef HAVE_LINK 222 if (unlink ((char *) atomic->lck) == -1) 223 rmdir ((char *) atomic->lck); 224#else 225 rmdir ((char *) atomic->lck); 226#endif 227} 228 229void 230FcAtomicDestroy (FcAtomic *atomic) 231{ 232 free (atomic); 233} 234#define __fcatomic__ 235#include "fcaliastail.h" 236#undef __fcatomic__ 237