Fallback to lstat() in case the filesystem doesn't support d_type in struct dirent
[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 #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)
72 static int
73 mkstemp (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
108 int
109 FcOpen(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
132 int
133 FcMakeTempfile (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
164 int32_t
165 FcRandom(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 #ifdef _AIX
174     static char *retval;
175     long res;
176 #endif
177
178     if (initialized != FcTrue)
179     {
180 #ifdef _AIX
181         initstate_r (time (NULL), statebuf, 256, &retval, &fcrandbuf);
182 #else
183         initstate_r (time (NULL), statebuf, 256, &fcrandbuf);
184 #endif
185         initialized = FcTrue;
186     }
187
188 #ifdef _AIX
189     random_r (&res, &fcrandbuf);
190     result = (int32_t)res;
191 #else
192     random_r (&fcrandbuf, &result);
193 #endif
194 #elif HAVE_RANDOM
195     static char statebuf[256];
196     char *state;
197     static FcBool initialized = FcFalse;
198
199     if (initialized != FcTrue)
200     {
201         state = initstate (time (NULL), statebuf, 256);
202         initialized = FcTrue;
203     }
204     else
205         state = setstate (statebuf);
206
207     result = random ();
208
209     setstate (state);
210 #elif HAVE_LRAND48
211     result = lrand48 ();
212 #elif HAVE_RAND_R
213     static unsigned int seed = time (NULL);
214
215     result = rand_r (&seed);
216 #elif HAVE_RAND
217     static FcBool initialized = FcFalse;
218
219     if (initialized != FcTrue)
220     {
221         srand (time (NULL));
222         initialized = FcTrue;
223     }
224     result = rand ();
225 #else
226 # error no random number generator function available.
227 #endif
228
229     return result;
230 }
231
232 #ifdef _WIN32
233 #include <direct.h>
234 #define mkdir(path,mode) _mkdir(path)
235 #endif
236
237 FcBool
238 FcMakeDirectory (const FcChar8 *dir)
239 {
240     FcChar8 *parent;
241     FcBool  ret;
242
243     if (strlen ((char *) dir) == 0)
244         return FcFalse;
245
246     parent = FcStrDirname (dir);
247     if (!parent)
248         return FcFalse;
249     if (access ((char *) parent, F_OK) == 0)
250         ret = mkdir ((char *) dir, 0755) == 0 && chmod ((char *) dir, 0755) == 0;
251     else if (access ((char *) parent, F_OK) == -1)
252         ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0755) == 0) && chmod ((char *) dir, 0755) == 0;
253     else
254         ret = FcFalse;
255     FcStrFree (parent);
256     return ret;
257 }