]> git.wh0rd.org - fontconfig.git/blob - src/fcatomic.c
Change RCS tag
[fontconfig.git] / src / fcatomic.c
1 /*
2 * $RCSId: xc/lib/fontconfig/src/fcatomic.c,v 1.2 2002/03/04 21:15:28 tsi Exp $
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 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 FcMemAlloc (FC_MEM_ATOMIC, total_len);
74
75 atomic->file = (FcChar8 *) (atomic + 1);
76 strcpy ((char *) atomic->file, (char *) file);
77
78 atomic->new = atomic->file + file_len + 1;
79 strcpy ((char *) atomic->new, (char *) file);
80 strcat ((char *) atomic->new, NEW_NAME);
81
82 atomic->lck = atomic->new + new_len + 1;
83 strcpy ((char *) atomic->lck, (char *) file);
84 strcat ((char *) atomic->lck, LCK_NAME);
85
86 atomic->tmp = atomic->lck + lck_len + 1;
87
88 return atomic;
89 }
90
91 FcBool
92 FcAtomicLock (FcAtomic *atomic)
93 {
94 int fd = -1;
95 FILE *f = 0;
96 int ret;
97 struct stat lck_stat;
98
99 strcpy ((char *) atomic->tmp, (char *) atomic->file);
100 strcat ((char *) atomic->tmp, TMP_NAME);
101 fd = mkstemp ((char *) atomic->tmp);
102 if (fd < 0)
103 return FcFalse;
104 f = fdopen (fd, "w");
105 if (!f)
106 {
107 close (fd);
108 unlink ((char *) atomic->tmp);
109 return FcFalse;
110 }
111 ret = fprintf (f, "%ld\n", (long)getpid());
112 if (ret <= 0)
113 {
114 fclose (f);
115 unlink ((char *) atomic->tmp);
116 return FcFalse;
117 }
118 if (fclose (f) == EOF)
119 {
120 unlink ((char *) atomic->tmp);
121 return FcFalse;
122 }
123 ret = link ((char *) atomic->tmp, (char *) atomic->lck);
124 (void) unlink ((char *) atomic->tmp);
125 if (ret < 0)
126 {
127 /*
128 * If the file is around and old (> 10 minutes),
129 * assume the lock is stale. This assumes that any
130 * machines sharing the same filesystem will have clocks
131 * reasonably close to each other.
132 */
133 if (stat ((char *) atomic->lck, &lck_stat) >= 0)
134 {
135 time_t now = time (0);
136 if ((long int) (now - lck_stat.st_mtime) > 10 * 60)
137 {
138 if (unlink ((char *) atomic->lck) == 0)
139 return FcAtomicLock (atomic);
140 }
141 }
142 return FcFalse;
143 }
144 (void) unlink ((char *) atomic->new);
145 return FcTrue;
146 }
147
148 FcChar8 *
149 FcAtomicNewFile (FcAtomic *atomic)
150 {
151 return atomic->new;
152 }
153
154 FcChar8 *
155 FcAtomicOrigFile (FcAtomic *atomic)
156 {
157 return atomic->file;
158 }
159
160 FcBool
161 FcAtomicReplaceOrig (FcAtomic *atomic)
162 {
163 if (rename ((char *) atomic->new, (char *) atomic->file) < 0)
164 return FcFalse;
165 return FcTrue;
166 }
167
168 void
169 FcAtomicDeleteNew (FcAtomic *atomic)
170 {
171 unlink ((char *) atomic->new);
172 }
173
174 void
175 FcAtomicUnlock (FcAtomic *atomic)
176 {
177 unlink ((char *) atomic->lck);
178 }
179
180 void
181 FcAtomicDestroy (FcAtomic *atomic)
182 {
183 FcMemFree (FC_MEM_ATOMIC, sizeof (FcAtomic) +
184 strlen ((char *) atomic->file) * 4 + 1 +
185 sizeof (NEW_NAME) + sizeof (LCK_NAME) +
186 sizeof (TMP_NAME));
187
188 free (atomic);
189 }