Fix mkstemp absence for some platform
[platform/upstream/fontconfig.git] / src / fccompat.c
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 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "fcint.h"
33
34 #include <errno.h>
35 #if HAVE_SYS_TYPES_H
36 #include <sys/types.h>
37 #endif
38 #if HAVE_SYS_STAT_H
39 #include <sys/stat.h>
40 #endif
41 #if HAVE_FCNTL_H
42 #include <fcntl.h>
43 #endif
44 #include <stdarg.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <time.h>
48
49 #ifdef O_CLOEXEC
50 #define FC_O_CLOEXEC O_CLOEXEC
51 #else
52 #define FC_O_CLOEXEC 0
53 #endif
54 #ifdef O_LARGEFILE
55 #define FC_O_LARGEFILE O_LARGEFILE
56 #else
57 #define FC_O_LARGEFILE 0
58 #endif
59 #ifdef O_BINARY
60 #define FC_O_BINARY O_BINARY
61 #else
62 #define FC_O_BINARY 0
63 #endif
64 #ifdef O_TEMPORARY
65 #define FC_O_TEMPORARY O_TEMPORARY
66 #else
67 #define FC_O_TEMPORARY 0
68 #endif
69 #ifdef O_NOINHERIT
70 #define FC_O_NOINHERIT O_NOINHERIT
71 #else
72 #define FC_O_NOINHERIT 0
73 #endif
74
75 #if !defined (HAVE_MKOSTEMP) && !defined(HAVE_MKSTEMP) && !defined(HAVE__MKTEMP_S)
76 static int
77 mkstemp (char *template)
78 {
79     static const char s[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
80     int fd, i;
81     size_t l;
82
83     if (template == NULL)
84     {
85         errno = EINVAL;
86         return -1;
87     }
88     l = strlen (template);
89     if (l < 6 || strcmp (&template[l - 6], "XXXXXX") != 0)
90     {
91         errno = EINVAL;
92         return -1;
93     }
94     do
95     {
96         errno = 0;
97         for (i = l - 6; i < l; i++)
98         {
99             int r = FcRandom ();
100             template[i] = s[r % 62];
101         }
102         fd = FcOpen (template, FC_O_BINARY | O_CREAT | O_EXCL | FC_O_TEMPORARY | FC_O_NOINHERIT | O_RDWR, 0600);
103     } while (fd < 0 && errno == EEXIST);
104     if (fd >= 0)
105         errno = 0;
106
107     return fd;
108 }
109 #define HAVE_MKSTEMP 1
110 #endif
111
112 int
113 FcOpen(const char *pathname, int flags, ...)
114 {
115     int fd = -1;
116
117     if (flags & O_CREAT)
118     {
119         va_list ap;
120         mode_t mode;
121
122         va_start(ap, flags);
123         mode = (mode_t) va_arg(ap, int);
124         va_end(ap);
125
126         fd = open(pathname, flags | FC_O_CLOEXEC | FC_O_LARGEFILE, mode);
127     }
128     else
129     {
130         fd = open(pathname, flags | FC_O_CLOEXEC | FC_O_LARGEFILE);
131     }
132
133     return fd;
134 }
135
136 int
137 FcMakeTempfile (char *template)
138 {
139     int fd = -1;
140
141 #if HAVE_MKOSTEMP
142     fd = mkostemp (template, FC_O_CLOEXEC);
143 #elif HAVE_MKSTEMP
144     fd = mkstemp (template);
145 #  ifdef F_DUPFD_CLOEXEC
146     if (fd != -1)
147     {
148         int newfd = fcntl(fd, F_DUPFD_CLOEXEC, STDIN_FILENO);
149
150         close(fd);
151         fd = newfd;
152     }
153 #  elif defined(FD_CLOEXEC)
154     if (fd != -1)
155     {
156         fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
157     }
158 #  endif
159 #elif HAVE__MKTEMP_S
160    if (_mktemp_s(template, strlen(template) + 1) != 0)
161        return -1;
162    fd = FcOpen(template, O_RDWR | O_EXCL | O_CREAT, 0600);
163 #else
164    /* warn at the runtime for just debugging purpose why something may
165     * goes wrong. mingw may not have one, but it shouldn't be reached since
166     * this function isn't used so far.
167     */
168    fprintf(stderr, "Fontconfig warning: No secure functions to create a temporary file\n");
169 #endif
170
171     return fd;
172 }
173
174 int32_t
175 FcRandom(void)
176 {
177     int32_t result;
178
179 #if HAVE_RANDOM_R
180     static struct random_data fcrandbuf;
181     static char statebuf[256];
182     static FcBool initialized = FcFalse;
183
184     if (initialized != FcTrue)
185     {
186         initstate_r(time(NULL), statebuf, 256, &fcrandbuf);
187         initialized = FcTrue;
188     }
189
190     random_r(&fcrandbuf, &result);
191 #elif HAVE_RANDOM
192     static char statebuf[256];
193     char *state;
194     static FcBool initialized = FcFalse;
195
196     if (initialized != FcTrue)
197     {
198         state = initstate(time(NULL), statebuf, 256);
199         initialized = FcTrue;
200     }
201     else
202         state = setstate(statebuf);
203
204     result = random();
205
206     setstate(state);
207 #elif HAVE_LRAND48
208     result = lrand48();
209 #elif HAVE_RAND_R
210     static unsigned int seed = time(NULL);
211
212     result = rand_r(&seed);
213 #elif HAVE_RAND
214     static FcBool initialized = FcFalse;
215
216     if (initialized != FcTrue)
217     {
218         srand(time(NULL));
219         initialized = FcTrue;
220     }
221     result = rand();
222 #else
223 # error no random number generator function available.
224 #endif
225
226     return result;
227 }