]> git.wh0rd.org Git - 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 }