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