fccompat.c revision a32e9e42
1/*
2 * fontconfig/src/fccompat.c
3 *
4 * Copyright © 2012 Red Hat, Inc.
5 *
6 * Author(s):
7 *  Akira TAGOH
8 *
9 * Permission to use, copy, modify, distribute, and sell this software and its
10 * documentation for any purpose is hereby granted without fee, provided that
11 * the above copyright notice appear in all copies and that both that
12 * copyright notice and this permission notice appear in supporting
13 * documentation, and that the name of the author(s) not be used in
14 * advertising or publicity pertaining to distribution of the software without
15 * specific, written prior permission.  The authors make no
16 * representations about the suitability of this software for any purpose.  It
17 * is provided "as is" without express or implied warranty.
18 *
19 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
20 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
21 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
22 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
23 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
24 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
25 * PERFORMANCE OF THIS SOFTWARE.
26 */
27
28#include "fcint.h"
29
30#include <errno.h>
31#if HAVE_SYS_TYPES_H
32#include <sys/types.h>
33#endif
34#if HAVE_SYS_STAT_H
35#include <sys/stat.h>
36#endif
37#if HAVE_FCNTL_H
38#include <fcntl.h>
39#endif
40#if HAVE_UNISTD_H
41#include <unistd.h>
42#endif
43#include <stdarg.h>
44#include <stdlib.h>
45#include <string.h>
46#include <time.h>
47
48#ifdef O_CLOEXEC
49#define FC_O_CLOEXEC O_CLOEXEC
50#else
51#define FC_O_CLOEXEC 0
52#endif
53#ifdef O_LARGEFILE
54#define FC_O_LARGEFILE O_LARGEFILE
55#else
56#define FC_O_LARGEFILE 0
57#endif
58#ifdef O_BINARY
59#define FC_O_BINARY O_BINARY
60#else
61#define FC_O_BINARY 0
62#endif
63#ifdef O_TEMPORARY
64#define FC_O_TEMPORARY O_TEMPORARY
65#else
66#define FC_O_TEMPORARY 0
67#endif
68#ifdef O_NOINHERIT
69#define FC_O_NOINHERIT O_NOINHERIT
70#else
71#define FC_O_NOINHERIT 0
72#endif
73
74#if !defined (HAVE_MKOSTEMP) && !defined(HAVE_MKSTEMP) && !defined(HAVE__MKTEMP_S)
75static int
76mkstemp (char *template)
77{
78    static const char s[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
79    int fd, i;
80    size_t l;
81
82    if (template == NULL)
83    {
84	errno = EINVAL;
85	return -1;
86    }
87    l = strlen (template);
88    if (l < 6 || strcmp (&template[l - 6], "XXXXXX") != 0)
89    {
90	errno = EINVAL;
91	return -1;
92    }
93    do
94    {
95	errno = 0;
96	for (i = l - 6; i < l; i++)
97	{
98	    int r = FcRandom ();
99	    template[i] = s[r % 62];
100	}
101	fd = FcOpen (template, FC_O_BINARY | O_CREAT | O_EXCL | FC_O_TEMPORARY | FC_O_NOINHERIT | O_RDWR, 0600);
102    } while (fd < 0 && errno == EEXIST);
103    if (fd >= 0)
104	errno = 0;
105
106    return fd;
107}
108#define HAVE_MKSTEMP 1
109#endif
110
111int
112FcOpen(const char *pathname, int flags, ...)
113{
114    int fd = -1;
115
116    if (flags & O_CREAT)
117    {
118	va_list ap;
119	mode_t mode;
120
121	va_start(ap, flags);
122	mode = (mode_t) va_arg(ap, int);
123	va_end(ap);
124
125	fd = open(pathname, flags | FC_O_CLOEXEC | FC_O_LARGEFILE, mode);
126    }
127    else
128    {
129	fd = open(pathname, flags | FC_O_CLOEXEC | FC_O_LARGEFILE);
130    }
131
132    return fd;
133}
134
135int
136FcMakeTempfile (char *template)
137{
138    int fd = -1;
139
140#if HAVE_MKOSTEMP
141    fd = mkostemp (template, FC_O_CLOEXEC);
142#elif HAVE_MKSTEMP
143    fd = mkstemp (template);
144#  ifdef F_DUPFD_CLOEXEC
145    if (fd != -1)
146    {
147	int newfd = fcntl(fd, F_DUPFD_CLOEXEC, STDIN_FILENO);
148
149	close(fd);
150	fd = newfd;
151    }
152#  elif defined(FD_CLOEXEC)
153    if (fd != -1)
154    {
155	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
156    }
157#  endif
158#elif HAVE__MKTEMP_S
159   if (_mktemp_s(template, strlen(template) + 1) != 0)
160       return -1;
161   fd = FcOpen(template, O_RDWR | O_EXCL | O_CREAT, 0600);
162#endif
163
164    return fd;
165}
166
167int32_t
168FcRandom(void)
169{
170    int32_t result;
171
172#if HAVE_RANDOM_R
173    static struct random_data fcrandbuf;
174    static char statebuf[256];
175    static FcBool initialized = FcFalse;
176#ifdef _AIX
177    static char *retval;
178    long res;
179#endif
180
181    if (initialized != FcTrue)
182    {
183#ifdef _AIX
184	initstate_r (time (NULL), statebuf, 256, &retval, &fcrandbuf);
185#else
186	initstate_r (time (NULL), statebuf, 256, &fcrandbuf);
187#endif
188	initialized = FcTrue;
189    }
190
191#ifdef _AIX
192    random_r (&res, &fcrandbuf);
193    result = (int32_t)res;
194#else
195    random_r (&fcrandbuf, &result);
196#endif
197#elif HAVE_RANDOM
198    static char statebuf[256];
199    char *state;
200    static FcBool initialized = FcFalse;
201
202    if (initialized != FcTrue)
203    {
204	state = initstate (time (NULL), statebuf, 256);
205	initialized = FcTrue;
206    }
207    else
208	state = setstate (statebuf);
209
210    result = random ();
211
212    setstate (state);
213#elif HAVE_LRAND48
214    result = lrand48 ();
215#elif HAVE_RAND_R
216    static unsigned int seed = time (NULL);
217
218    result = rand_r (&seed);
219#elif HAVE_RAND
220    static FcBool initialized = FcFalse;
221
222    if (initialized != FcTrue)
223    {
224	srand (time (NULL));
225	initialized = FcTrue;
226    }
227    result = rand ();
228#else
229# error no random number generator function available.
230#endif
231
232    return result;
233}
234
235#ifdef _WIN32
236#include <direct.h>
237#define mkdir(path,mode) _mkdir(path)
238#endif
239
240FcBool
241FcMakeDirectory (const FcChar8 *dir)
242{
243    FcChar8 *parent;
244    FcBool  ret;
245
246    if (strlen ((char *) dir) == 0)
247	return FcFalse;
248
249    parent = FcStrDirname (dir);
250    if (!parent)
251	return FcFalse;
252    if (access ((char *) parent, F_OK) == 0)
253	ret = mkdir ((char *) dir, 0755) == 0 && chmod ((char *) dir, 0755) == 0;
254    else if (access ((char *) parent, F_OK) == -1)
255	ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0755) == 0) && chmod ((char *) dir, 0755) == 0;
256    else
257	ret = FcFalse;
258    FcStrFree (parent);
259    return ret;
260}
261
262ssize_t
263FcReadLink (const FcChar8 *pathname,
264	    FcChar8       *buf,
265	    size_t         bufsiz)
266{
267#ifdef HAVE_READLINK
268    return readlink ((const char *) pathname, (char *)buf, bufsiz);
269#else
270    /* XXX: this function is only used for FcConfigRealFilename() so far
271     * and returning -1 as an error still just works.
272     */
273    errno = ENOSYS;
274    return -1;
275#endif
276}
277
278#define __fccompat__
279#include "fcaliastail.h"
280#undef __fccompat__
281