]> git.wh0rd.org - fontconfig.git/blob - src/fcatomic.c
Add fcatomic.c
[fontconfig.git] / src / fcatomic.c
1 /*
2 * $XFree86: $
3 *
4 * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
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 Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes 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 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD 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 * Four files:
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
46 #include "fcint.h"
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <fcntl.h>
50 #include <unistd.h>
51 #include <stdlib.h>
52 #include <time.h>
53
54 #define NEW_NAME ".NEW"
55 #define LCK_NAME ".LCK"
56 #define TMP_NAME ".TMP-XXXXXX"
57
58 FcAtomic *
59 FcAtomicCreate (const FcChar8 *file)
60 {
61 int file_len = strlen ((char *) file);
62 int new_len = file_len + sizeof (NEW_NAME);
63 int lck_len = file_len + sizeof (LCK_NAME);
64 int tmp_len = file_len + sizeof (TMP_NAME);
65 int total_len = (sizeof (FcAtomic) +
66 file_len + 1 +
67 new_len + 1 +
68 lck_len + 1 +
69 tmp_len + 1);
70 FcAtomic *atomic = malloc (total_len);
71 if (!atomic)
72 return 0;
73
74 atomic->file = (FcChar8 *) (atomic + 1);
75 strcpy ((char *) atomic->file, (char *) file);
76
77 atomic->new = atomic->file + file_len + 1;
78 strcpy ((char *) atomic->new, (char *) file);
79 strcat ((char *) atomic->new, NEW_NAME);
80
81 atomic->lck = atomic->new + new_len + 1;
82 strcpy ((char *) atomic->lck, (char *) file);
83 strcat ((char *) atomic->lck, LCK_NAME);
84
85 atomic->tmp = atomic->lck + lck_len + 1;
86
87 return atomic;
88 }
89
90 FcBool
91 FcAtomicLock (FcAtomic *atomic)
92 {
93 int fd = -1;
94 FILE *f = 0;
95 int ret;
96 struct stat lck_stat;
97
98 strcpy ((char *) atomic->tmp, (char *) atomic->file);
99 strcat ((char *) atomic->tmp, TMP_NAME);
100 fd = mkstemp ((char *) atomic->tmp);
101 if (fd < 0)
102 return FcFalse;
103 f = fdopen (fd, "w");
104 if (!f)
105 {
106 close (fd);
107 unlink ((char *) atomic->tmp);
108 return FcFalse;
109 }
110 ret = fprintf (f, "%d\n", getpid());
111 if (ret <= 0)
112 {
113 fclose (f);
114 unlink ((char *) atomic->tmp);
115 return FcFalse;
116 }
117 if (fclose (f) == EOF)
118 {
119 unlink ((char *) atomic->tmp);
120 return FcFalse;
121 }
122 ret = link ((char *) atomic->tmp, (char *) atomic->lck);
123 (void) unlink ((char *) atomic->tmp);
124 if (ret < 0)
125 {
126 /*
127 * If the file is around and old (> 10 minutes),
128 * assume the lock is stale. This assumes that any
129 * machines sharing the same filesystem will have clocks
130 * reasonably close to each other.
131 */
132 if (stat ((char *) atomic->lck, &lck_stat) >= 0)
133 {
134 time_t now = time (0);
135 if ((long int) (now - lck_stat.st_mtime) > 10 * 60)
136 {
137 if (unlink ((char *) atomic->lck) == 0)
138 return FcAtomicLock (atomic);
139 }
140 }
141 return FcFalse;
142 }
143 (void) unlink ((char *) atomic->new);
144 return FcTrue;
145 }
146
147 FcChar8 *
148 FcAtomicNewFile (FcAtomic *atomic)
149 {
150 return atomic->new;
151 }
152
153 FcChar8 *
154 FcAtomicOrigFile (FcAtomic *atomic)
155 {
156 return atomic->file;
157 }
158
159 FcBool
160 FcAtomicReplaceOrig (FcAtomic *atomic)
161 {
162 if (rename ((char *) atomic->new, (char *) atomic->file) < 0)
163 return FcFalse;
164 return FcTrue;
165 }
166
167 void
168 FcAtomicDeleteNew (FcAtomic *atomic)
169 {
170 unlink ((char *) atomic->new);
171 }
172
173 void
174 FcAtomicUnlock (FcAtomic *atomic)
175 {
176 unlink ((char *) atomic->lck);
177 }
178
179 void
180 FcAtomicDestroy (FcAtomic *atomic)
181 {
182 free (atomic);
183 }