]> git.wh0rd.org - fontconfig.git/blame - src/fcatomic.c
fc-cache: add a --root option
[fontconfig.git] / src / fcatomic.c
CommitLineData
a391da8f 1/*
317b8492 2 * fontconfig/src/fcatomic.c
a391da8f 3 *
46b51147 4 * Copyright © 2002 Keith Packard
a391da8f
KP
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
5aaf466d 10 * documentation, and that the name of the author(s) not be used in
a391da8f 11 * advertising or publicity pertaining to distribution of the software without
5aaf466d 12 * specific, written prior permission. The authors make no
a391da8f
KP
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
3074a73b 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
a391da8f 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
3074a73b 18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
a391da8f
KP
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 *
daeed6e0 33 * On Unix, four files are used:
a391da8f
KP
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
daeed6e0
TL
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.
a391da8f
KP
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
daeed6e0
TL
58#ifdef _WIN32
59#define mkdir(path,mode) _mkdir(path)
60#endif
61
a391da8f
KP
62#define NEW_NAME ".NEW"
63#define LCK_NAME ".LCK"
64#define TMP_NAME ".TMP-XXXXXX"
65
66FcAtomic *
67FcAtomicCreate (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;
9dac3c59 81 FcMemAlloc (FC_MEM_ATOMIC, total_len);
594dcef0 82
a391da8f
KP
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
99FcBool
100FcAtomicLock (FcAtomic *atomic)
d0471dd2
MF
101{
102 return FcAtomicLock2 (FcConfigGetCurrent (), atomic);
103}
104
105FcBool
106FcAtomicLock2 (FcConfig *config, FcAtomic *atomic)
a391da8f
KP
107{
108 int fd = -1;
109 FILE *f = 0;
110 int ret;
111 struct stat lck_stat;
112
daeed6e0 113#ifdef HAVE_LINK
a391da8f
KP
114 strcpy ((char *) atomic->tmp, (char *) atomic->file);
115 strcat ((char *) atomic->tmp, TMP_NAME);
116 fd = mkstemp ((char *) atomic->tmp);
117 if (fd < 0)
118 return FcFalse;
119 f = fdopen (fd, "w");
120 if (!f)
121 {
122 close (fd);
123 unlink ((char *) atomic->tmp);
124 return FcFalse;
125 }
8c7b2a9d 126 ret = fprintf (f, "%ld\n", (long)getpid());
a391da8f
KP
127 if (ret <= 0)
128 {
129 fclose (f);
130 unlink ((char *) atomic->tmp);
131 return FcFalse;
132 }
133 if (fclose (f) == EOF)
134 {
135 unlink ((char *) atomic->tmp);
136 return FcFalse;
137 }
138 ret = link ((char *) atomic->tmp, (char *) atomic->lck);
139 (void) unlink ((char *) atomic->tmp);
daeed6e0
TL
140#else
141 ret = mkdir ((char *) atomic->lck, 0600);
142#endif
a391da8f
KP
143 if (ret < 0)
144 {
145 /*
146 * If the file is around and old (> 10 minutes),
147 * assume the lock is stale. This assumes that any
148 * machines sharing the same filesystem will have clocks
149 * reasonably close to each other.
150 */
d0471dd2 151 if (FcStat (config, atomic->lck, &lck_stat) >= 0)
a391da8f
KP
152 {
153 time_t now = time (0);
154 if ((long int) (now - lck_stat.st_mtime) > 10 * 60)
155 {
daeed6e0 156#ifdef HAVE_LINK
a391da8f 157 if (unlink ((char *) atomic->lck) == 0)
d0471dd2 158 return FcAtomicLock2 (config, atomic);
daeed6e0
TL
159#else
160 if (rmdir ((char *) atomic->lck) == 0)
d0471dd2 161 return FcAtomicLock2 (config, atomic);
daeed6e0 162#endif
a391da8f
KP
163 }
164 }
165 return FcFalse;
166 }
167 (void) unlink ((char *) atomic->new);
168 return FcTrue;
169}
170
171FcChar8 *
172FcAtomicNewFile (FcAtomic *atomic)
173{
174 return atomic->new;
175}
176
177FcChar8 *
178FcAtomicOrigFile (FcAtomic *atomic)
179{
180 return atomic->file;
181}
182
183FcBool
184FcAtomicReplaceOrig (FcAtomic *atomic)
185{
ba76916f
PL
186#ifdef _WIN32
187 unlink (atomic->file);
188#endif
a391da8f
KP
189 if (rename ((char *) atomic->new, (char *) atomic->file) < 0)
190 return FcFalse;
191 return FcTrue;
192}
193
194void
195FcAtomicDeleteNew (FcAtomic *atomic)
196{
197 unlink ((char *) atomic->new);
198}
199
200void
201FcAtomicUnlock (FcAtomic *atomic)
202{
daeed6e0 203#ifdef HAVE_LINK
a391da8f 204 unlink ((char *) atomic->lck);
daeed6e0
TL
205#else
206 rmdir ((char *) atomic->lck);
207#endif
a391da8f
KP
208}
209
210void
211FcAtomicDestroy (FcAtomic *atomic)
212{
9dac3c59 213 FcMemFree (FC_MEM_ATOMIC, sizeof (FcAtomic) +
13a14cbf 214 strlen ((char *) atomic->file) * 4 + 4 +
594dcef0 215 sizeof (NEW_NAME) + sizeof (LCK_NAME) +
9dac3c59
KP
216 sizeof (TMP_NAME));
217
a391da8f
KP
218 free (atomic);
219}
23816bf9
KP
220#define __fcatomic__
221#include "fcaliastail.h"
222#undef __fcatomic__