]>
Commit | Line | Data |
---|---|---|
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 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 | * 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 | #include "fcint.h" | |
51 | #include <sys/types.h> | |
52 | #include <sys/stat.h> | |
53 | #include <fcntl.h> | |
54 | #include <unistd.h> | |
55 | #include <stdlib.h> | |
56 | #include <time.h> | |
57 | ||
58 | #ifdef _WIN32 | |
59 | #define mkdir(path,mode) _mkdir(path) | |
60 | #endif | |
61 | ||
62 | #define NEW_NAME ".NEW" | |
63 | #define LCK_NAME ".LCK" | |
64 | #define TMP_NAME ".TMP-XXXXXX" | |
65 | ||
66 | FcAtomic * | |
67 | FcAtomicCreate (const FcChar8 *file) | |
68 | { | |
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) + | |
74 | file_len + 1 + | |
75 | new_len + 1 + | |
76 | lck_len + 1 + | |
77 | tmp_len + 1); | |
78 | FcAtomic *atomic = malloc (total_len); | |
79 | if (!atomic) | |
80 | return 0; | |
81 | FcMemAlloc (FC_MEM_ATOMIC, total_len); | |
82 | ||
83 | atomic->file = (FcChar8 *) (atomic + 1); | |
84 | strcpy ((char *) atomic->file, (char *) file); | |
85 | ||
86 | atomic->new = atomic->file + file_len + 1; | |
87 | strcpy ((char *) atomic->new, (char *) file); | |
88 | strcat ((char *) atomic->new, NEW_NAME); | |
89 | ||
90 | atomic->lck = atomic->new + new_len + 1; | |
91 | strcpy ((char *) atomic->lck, (char *) file); | |
92 | strcat ((char *) atomic->lck, LCK_NAME); | |
93 | ||
94 | atomic->tmp = atomic->lck + lck_len + 1; | |
95 | ||
96 | return atomic; | |
97 | } | |
98 | ||
99 | FcBool | |
100 | FcAtomicLock (FcAtomic *atomic) | |
101 | { | |
102 | int fd = -1; | |
103 | FILE *f = 0; | |
104 | int ret; | |
105 | struct stat lck_stat; | |
106 | ||
107 | #ifdef HAVE_LINK | |
108 | strcpy ((char *) atomic->tmp, (char *) atomic->file); | |
109 | strcat ((char *) atomic->tmp, TMP_NAME); | |
110 | fd = mkstemp ((char *) atomic->tmp); | |
111 | if (fd < 0) | |
112 | return FcFalse; | |
113 | f = fdopen (fd, "w"); | |
114 | if (!f) | |
115 | { | |
116 | close (fd); | |
117 | unlink ((char *) atomic->tmp); | |
118 | return FcFalse; | |
119 | } | |
120 | ret = fprintf (f, "%ld\n", (long)getpid()); | |
121 | if (ret <= 0) | |
122 | { | |
123 | fclose (f); | |
124 | unlink ((char *) atomic->tmp); | |
125 | return FcFalse; | |
126 | } | |
127 | if (fclose (f) == EOF) | |
128 | { | |
129 | unlink ((char *) atomic->tmp); | |
130 | return FcFalse; | |
131 | } | |
132 | ret = link ((char *) atomic->tmp, (char *) atomic->lck); | |
133 | (void) unlink ((char *) atomic->tmp); | |
134 | #else | |
135 | ret = mkdir ((char *) atomic->lck, 0600); | |
136 | #endif | |
137 | if (ret < 0) | |
138 | { | |
139 | /* | |
140 | * If the file is around and old (> 10 minutes), | |
141 | * assume the lock is stale. This assumes that any | |
142 | * machines sharing the same filesystem will have clocks | |
143 | * reasonably close to each other. | |
144 | */ | |
145 | if (FcStat ((char *) atomic->lck, &lck_stat) >= 0) | |
146 | { | |
147 | time_t now = time (0); | |
148 | if ((long int) (now - lck_stat.st_mtime) > 10 * 60) | |
149 | { | |
150 | #ifdef HAVE_LINK | |
151 | if (unlink ((char *) atomic->lck) == 0) | |
152 | return FcAtomicLock (atomic); | |
153 | #else | |
154 | if (rmdir ((char *) atomic->lck) == 0) | |
155 | return FcAtomicLock (atomic); | |
156 | #endif | |
157 | } | |
158 | } | |
159 | return FcFalse; | |
160 | } | |
161 | (void) unlink ((char *) atomic->new); | |
162 | return FcTrue; | |
163 | } | |
164 | ||
165 | FcChar8 * | |
166 | FcAtomicNewFile (FcAtomic *atomic) | |
167 | { | |
168 | return atomic->new; | |
169 | } | |
170 | ||
171 | FcChar8 * | |
172 | FcAtomicOrigFile (FcAtomic *atomic) | |
173 | { | |
174 | return atomic->file; | |
175 | } | |
176 | ||
177 | FcBool | |
178 | FcAtomicReplaceOrig (FcAtomic *atomic) | |
179 | { | |
180 | #ifdef _WIN32 | |
181 | unlink (atomic->file); | |
182 | #endif | |
183 | if (rename ((char *) atomic->new, (char *) atomic->file) < 0) | |
184 | return FcFalse; | |
185 | return FcTrue; | |
186 | } | |
187 | ||
188 | void | |
189 | FcAtomicDeleteNew (FcAtomic *atomic) | |
190 | { | |
191 | unlink ((char *) atomic->new); | |
192 | } | |
193 | ||
194 | void | |
195 | FcAtomicUnlock (FcAtomic *atomic) | |
196 | { | |
197 | #ifdef HAVE_LINK | |
198 | unlink ((char *) atomic->lck); | |
199 | #else | |
200 | rmdir ((char *) atomic->lck); | |
201 | #endif | |
202 | } | |
203 | ||
204 | void | |
205 | FcAtomicDestroy (FcAtomic *atomic) | |
206 | { | |
207 | FcMemFree (FC_MEM_ATOMIC, sizeof (FcAtomic) + | |
208 | strlen ((char *) atomic->file) * 4 + 4 + | |
209 | sizeof (NEW_NAME) + sizeof (LCK_NAME) + | |
210 | sizeof (TMP_NAME)); | |
211 | ||
212 | free (atomic); | |
213 | } | |
214 | #define __fcatomic__ | |
215 | #include "fcaliastail.h" | |
216 | #undef __fcatomic__ |