fccompat.c revision 6fc018e4
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#include <stdarg.h>
41#include <stdlib.h>
42#include <string.h>
43#include <time.h>
44
45#ifdef O_CLOEXEC
46#define FC_O_CLOEXEC O_CLOEXEC
47#else
48#define FC_O_CLOEXEC 0
49#endif
50#ifdef O_LARGEFILE
51#define FC_O_LARGEFILE O_LARGEFILE
52#else
53#define FC_O_LARGEFILE 0
54#endif
55#ifdef O_BINARY
56#define FC_O_BINARY O_BINARY
57#else
58#define FC_O_BINARY 0
59#endif
60#ifdef O_TEMPORARY
61#define FC_O_TEMPORARY O_TEMPORARY
62#else
63#define FC_O_TEMPORARY 0
64#endif
65#ifdef O_NOINHERIT
66#define FC_O_NOINHERIT O_NOINHERIT
67#else
68#define FC_O_NOINHERIT 0
69#endif
70
71#if !defined (HAVE_MKOSTEMP) && !defined(HAVE_MKSTEMP) && !defined(HAVE__MKTEMP_S)
72static int
73mkstemp (char *template)
74{
75    static const char s[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
76    int fd, i;
77    size_t l;
78
79    if (template == NULL)
80    {
81	errno = EINVAL;
82	return -1;
83    }
84    l = strlen (template);
85    if (l < 6 || strcmp (&template[l - 6], "XXXXXX") != 0)
86    {
87	errno = EINVAL;
88	return -1;
89    }
90    do
91    {
92	errno = 0;
93	for (i = l - 6; i < l; i++)
94	{
95	    int r = FcRandom ();
96	    template[i] = s[r % 62];
97	}
98	fd = FcOpen (template, FC_O_BINARY | O_CREAT | O_EXCL | FC_O_TEMPORARY | FC_O_NOINHERIT | O_RDWR, 0600);
99    } while (fd < 0 && errno == EEXIST);
100    if (fd >= 0)
101	errno = 0;
102
103    return fd;
104}
105#define HAVE_MKSTEMP 1
106#endif
107
108int
109FcOpen(const char *pathname, int flags, ...)
110{
111    int fd = -1;
112
113    if (flags & O_CREAT)
114    {
115	va_list ap;
116	mode_t mode;
117
118	va_start(ap, flags);
119	mode = (mode_t) va_arg(ap, int);
120	va_end(ap);
121
122	fd = open(pathname, flags | FC_O_CLOEXEC | FC_O_LARGEFILE, mode);
123    }
124    else
125    {
126	fd = open(pathname, flags | FC_O_CLOEXEC | FC_O_LARGEFILE);
127    }
128
129    return fd;
130}
131
132int
133FcMakeTempfile (char *template)
134{
135    int fd = -1;
136
137#if HAVE_MKOSTEMP
138    fd = mkostemp (template, FC_O_CLOEXEC);
139#elif HAVE_MKSTEMP
140    fd = mkstemp (template);
141#  ifdef F_DUPFD_CLOEXEC
142    if (fd != -1)
143    {
144	int newfd = fcntl(fd, F_DUPFD_CLOEXEC, STDIN_FILENO);
145
146	close(fd);
147	fd = newfd;
148    }
149#  elif defined(FD_CLOEXEC)
150    if (fd != -1)
151    {
152	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
153    }
154#  endif
155#elif HAVE__MKTEMP_S
156   if (_mktemp_s(template, strlen(template) + 1) != 0)
157       return -1;
158   fd = FcOpen(template, O_RDWR | O_EXCL | O_CREAT, 0600);
159#endif
160
161    return fd;
162}
163
164int32_t
165FcRandom(void)
166{
167    int32_t result;
168
169#if HAVE_RANDOM_R
170    static struct random_data fcrandbuf;
171    static char statebuf[256];
172    static FcBool initialized = FcFalse;
173
174    if (initialized != FcTrue)
175    {
176	initstate_r(time(NULL), statebuf, 256, &fcrandbuf);
177	initialized = FcTrue;
178    }
179
180    random_r(&fcrandbuf, &result);
181#elif HAVE_RANDOM
182    static char statebuf[256];
183    char *state;
184    static FcBool initialized = FcFalse;
185
186    if (initialized != FcTrue)
187    {
188	state = initstate(time(NULL), statebuf, 256);
189	initialized = FcTrue;
190    }
191    else
192	state = setstate(statebuf);
193
194    result = random();
195
196    setstate(state);
197#elif HAVE_LRAND48
198    result = lrand48();
199#elif HAVE_RAND_R
200    static unsigned int seed = time(NULL);
201
202    result = rand_r(&seed);
203#elif HAVE_RAND
204    static FcBool initialized = FcFalse;
205
206    if (initialized != FcTrue)
207    {
208	srand(time(NULL));
209	initialized = FcTrue;
210    }
211    result = rand();
212#else
213# error no random number generator function available.
214#endif
215
216    return result;
217}
218
219#ifdef _WIN32
220#include <direct.h>
221#define mkdir(path,mode) _mkdir(path)
222#endif
223
224FcBool
225FcMakeDirectory (const FcChar8 *dir)
226{
227    FcChar8 *parent;
228    FcBool  ret;
229
230    if (strlen ((char *) dir) == 0)
231	return FcFalse;
232
233    parent = FcStrDirname (dir);
234    if (!parent)
235	return FcFalse;
236    if (access ((char *) parent, F_OK) == 0)
237	ret = mkdir ((char *) dir, 0755) == 0 && chmod ((char *) dir, 0755) == 0;
238    else if (access ((char *) parent, F_OK) == -1)
239	ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0755) == 0) && chmod ((char *) dir, 0755) == 0;
240    else
241	ret = FcFalse;
242    FcStrFree (parent);
243    return ret;
244}
245