2 * fontconfig/src/fcatomic.c
4 * Copyright © 2002 Keith Packard
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.
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.
28 * Lock cache and configuration files for atomic update
30 * Uses only regular filesystem calls so it should
31 * work even in the absense of functioning file locking
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
37 * tmp - a temporary file made unique with mkstemp
39 * Here's how it works:
40 * Create 'tmp' and store our PID in it
41 * Attempt to link it to 'lck'
43 * If the link succeeded, the lock is held
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
51 #include <sys/types.h>
59 #define mkdir(path,mode) _mkdir(path)
62 #define NEW_NAME ".NEW"
63 #define LCK_NAME ".LCK"
64 #define TMP_NAME ".TMP-XXXXXX"
67 FcAtomicCreate (const FcChar8 *file)
69 int file_len = strlen ((char *) file);
70 int new_len = file_len + sizeof (NEW_NAME);
71 int lck_len = file_len + sizeof (LCK_NAME);
72 int tmp_len = file_len + sizeof (TMP_NAME);
73 int total_len = (sizeof (FcAtomic) +
78 FcAtomic *atomic = malloc (total_len);
82 atomic->file = (FcChar8 *) (atomic + 1);
83 strcpy ((char *) atomic->file, (char *) file);
85 atomic->new = atomic->file + file_len + 1;
86 strcpy ((char *) atomic->new, (char *) file);
87 strcat ((char *) atomic->new, NEW_NAME);
89 atomic->lck = atomic->new + new_len + 1;
90 strcpy ((char *) atomic->lck, (char *) file);
91 strcat ((char *) atomic->lck, LCK_NAME);
93 atomic->tmp = atomic->lck + lck_len + 1;
99 FcAtomicLock (FcAtomic *atomic)
102 struct stat lck_stat;
107 FcBool no_link = FcFalse;
109 strcpy ((char *) atomic->tmp, (char *) atomic->file);
110 strcat ((char *) atomic->tmp, TMP_NAME);
111 fd = mkstemp ((char *) atomic->tmp);
114 f = fdopen (fd, "w");
118 unlink ((char *) atomic->tmp);
121 ret = fprintf (f, "%ld\n", (long)getpid());
125 unlink ((char *) atomic->tmp);
128 if (fclose (f) == EOF)
130 unlink ((char *) atomic->tmp);
133 ret = link ((char *) atomic->tmp, (char *) atomic->lck);
134 if (ret < 0 && errno == EPERM)
136 /* the filesystem where atomic->lck points to may not supports
137 * the hard link. so better try to fallback
139 ret = mkdir ((char *) atomic->lck, 0600);
142 (void) unlink ((char *) atomic->tmp);
144 ret = mkdir ((char *) atomic->lck, 0600);
149 * If the file is around and old (> 10 minutes),
150 * assume the lock is stale. This assumes that any
151 * machines sharing the same filesystem will have clocks
152 * reasonably close to each other.
154 if (FcStat (atomic->lck, &lck_stat) >= 0)
156 time_t now = time (0);
157 if ((long int) (now - lck_stat.st_mtime) > 10 * 60)
162 if (rmdir ((char *) atomic->lck) == 0)
163 return FcAtomicLock (atomic);
167 if (unlink ((char *) atomic->lck) == 0)
168 return FcAtomicLock (atomic);
171 if (rmdir ((char *) atomic->lck) == 0)
172 return FcAtomicLock (atomic);
178 (void) unlink ((char *) atomic->new);
183 FcAtomicNewFile (FcAtomic *atomic)
189 FcAtomicOrigFile (FcAtomic *atomic)
195 FcAtomicReplaceOrig (FcAtomic *atomic)
198 unlink ((const char *) atomic->file);
200 if (rename ((char *) atomic->new, (char *) atomic->file) < 0)
206 FcAtomicDeleteNew (FcAtomic *atomic)
208 unlink ((char *) atomic->new);
212 FcAtomicUnlock (FcAtomic *atomic)
215 if (unlink ((char *) atomic->lck) == -1)
216 rmdir ((char *) atomic->lck);
218 rmdir ((char *) atomic->lck);
223 FcAtomicDestroy (FcAtomic *atomic)
228 #include "fcaliastail.h"