1c9710b42Smrg/*
2c9710b42Smrg * fontconfig/src/fccompat.c
3c9710b42Smrg *
4c9710b42Smrg * Copyright © 2012 Red Hat, Inc.
5c9710b42Smrg *
6c9710b42Smrg * Author(s):
7c9710b42Smrg *  Akira TAGOH
8c9710b42Smrg *
9c9710b42Smrg * Permission to use, copy, modify, distribute, and sell this software and its
10c9710b42Smrg * documentation for any purpose is hereby granted without fee, provided that
11c9710b42Smrg * the above copyright notice appear in all copies and that both that
12c9710b42Smrg * copyright notice and this permission notice appear in supporting
13c9710b42Smrg * documentation, and that the name of the author(s) not be used in
14c9710b42Smrg * advertising or publicity pertaining to distribution of the software without
15c9710b42Smrg * specific, written prior permission.  The authors make no
16c9710b42Smrg * representations about the suitability of this software for any purpose.  It
17c9710b42Smrg * is provided "as is" without express or implied warranty.
18c9710b42Smrg *
19c9710b42Smrg * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
20c9710b42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
21c9710b42Smrg * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
22c9710b42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
23c9710b42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
24c9710b42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
25c9710b42Smrg * PERFORMANCE OF THIS SOFTWARE.
26c9710b42Smrg */
27c9710b42Smrg
28c9710b42Smrg#include "fcint.h"
29c9710b42Smrg
30c9710b42Smrg#include <errno.h>
31c9710b42Smrg#if HAVE_SYS_TYPES_H
32c9710b42Smrg#include <sys/types.h>
33c9710b42Smrg#endif
34c9710b42Smrg#if HAVE_SYS_STAT_H
35c9710b42Smrg#include <sys/stat.h>
36c9710b42Smrg#endif
37c9710b42Smrg#if HAVE_FCNTL_H
38c9710b42Smrg#include <fcntl.h>
39c9710b42Smrg#endif
40a32e9e42Smrg#if HAVE_UNISTD_H
41a32e9e42Smrg#include <unistd.h>
42a32e9e42Smrg#endif
43c9710b42Smrg#include <stdarg.h>
44c9710b42Smrg#include <stdlib.h>
45c9710b42Smrg#include <string.h>
46c9710b42Smrg#include <time.h>
47c9710b42Smrg
48c9710b42Smrg#ifdef O_CLOEXEC
49c9710b42Smrg#define FC_O_CLOEXEC O_CLOEXEC
50c9710b42Smrg#else
51c9710b42Smrg#define FC_O_CLOEXEC 0
52c9710b42Smrg#endif
53c9710b42Smrg#ifdef O_LARGEFILE
54c9710b42Smrg#define FC_O_LARGEFILE O_LARGEFILE
55c9710b42Smrg#else
56c9710b42Smrg#define FC_O_LARGEFILE 0
57c9710b42Smrg#endif
58c9710b42Smrg#ifdef O_BINARY
59c9710b42Smrg#define FC_O_BINARY O_BINARY
60c9710b42Smrg#else
61c9710b42Smrg#define FC_O_BINARY 0
62c9710b42Smrg#endif
63c9710b42Smrg#ifdef O_TEMPORARY
64c9710b42Smrg#define FC_O_TEMPORARY O_TEMPORARY
65c9710b42Smrg#else
66c9710b42Smrg#define FC_O_TEMPORARY 0
67c9710b42Smrg#endif
68c9710b42Smrg#ifdef O_NOINHERIT
69c9710b42Smrg#define FC_O_NOINHERIT O_NOINHERIT
70c9710b42Smrg#else
71c9710b42Smrg#define FC_O_NOINHERIT 0
72c9710b42Smrg#endif
73c9710b42Smrg
74a4e54154Smrg#ifndef HAVE_UNISTD_H
75a4e54154Smrg/* Values for the second argument to access. These may be OR'd together. */
76a4e54154Smrg#ifndef R_OK
77a4e54154Smrg#define R_OK    4       /* Test for read permission.  */
78a4e54154Smrg#endif
79a4e54154Smrg#ifndef W_OK
80a4e54154Smrg#define W_OK    2       /* Test for write permission.  */
81a4e54154Smrg#endif
82a4e54154Smrg#ifndef F_OK
83a4e54154Smrg#define F_OK    0       /* Test for existence.  */
84a4e54154Smrg#endif
85a4e54154Smrg
86a4e54154Smrgtypedef int mode_t;
87a4e54154Smrg#endif /* !HAVE_UNISTD_H */
88a4e54154Smrg
89c9710b42Smrg#if !defined (HAVE_MKOSTEMP) && !defined(HAVE_MKSTEMP) && !defined(HAVE__MKTEMP_S)
90c9710b42Smrgstatic int
91c9710b42Smrgmkstemp (char *template)
92c9710b42Smrg{
93c9710b42Smrg    static const char s[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
94c9710b42Smrg    int fd, i;
95c9710b42Smrg    size_t l;
96c9710b42Smrg
97c9710b42Smrg    if (template == NULL)
98c9710b42Smrg    {
99c9710b42Smrg	errno = EINVAL;
100c9710b42Smrg	return -1;
101c9710b42Smrg    }
102c9710b42Smrg    l = strlen (template);
103c9710b42Smrg    if (l < 6 || strcmp (&template[l - 6], "XXXXXX") != 0)
104c9710b42Smrg    {
105c9710b42Smrg	errno = EINVAL;
106c9710b42Smrg	return -1;
107c9710b42Smrg    }
108c9710b42Smrg    do
109c9710b42Smrg    {
110c9710b42Smrg	errno = 0;
111c9710b42Smrg	for (i = l - 6; i < l; i++)
112c9710b42Smrg	{
113c9710b42Smrg	    int r = FcRandom ();
114c9710b42Smrg	    template[i] = s[r % 62];
115c9710b42Smrg	}
116c9710b42Smrg	fd = FcOpen (template, FC_O_BINARY | O_CREAT | O_EXCL | FC_O_TEMPORARY | FC_O_NOINHERIT | O_RDWR, 0600);
117c9710b42Smrg    } while (fd < 0 && errno == EEXIST);
118c9710b42Smrg    if (fd >= 0)
119c9710b42Smrg	errno = 0;
120c9710b42Smrg
121c9710b42Smrg    return fd;
122c9710b42Smrg}
123c9710b42Smrg#define HAVE_MKSTEMP 1
124c9710b42Smrg#endif
125c9710b42Smrg
126c9710b42Smrgint
127c9710b42SmrgFcOpen(const char *pathname, int flags, ...)
128c9710b42Smrg{
129c9710b42Smrg    int fd = -1;
130c9710b42Smrg
131c9710b42Smrg    if (flags & O_CREAT)
132c9710b42Smrg    {
133c9710b42Smrg	va_list ap;
134c9710b42Smrg	mode_t mode;
135c9710b42Smrg
136c9710b42Smrg	va_start(ap, flags);
137c9710b42Smrg	mode = (mode_t) va_arg(ap, int);
138c9710b42Smrg	va_end(ap);
139c9710b42Smrg
140c9710b42Smrg	fd = open(pathname, flags | FC_O_CLOEXEC | FC_O_LARGEFILE, mode);
141c9710b42Smrg    }
142c9710b42Smrg    else
143c9710b42Smrg    {
144c9710b42Smrg	fd = open(pathname, flags | FC_O_CLOEXEC | FC_O_LARGEFILE);
145c9710b42Smrg    }
146c9710b42Smrg
147c9710b42Smrg    return fd;
148c9710b42Smrg}
149c9710b42Smrg
150c9710b42Smrgint
151c9710b42SmrgFcMakeTempfile (char *template)
152c9710b42Smrg{
153c9710b42Smrg    int fd = -1;
154c9710b42Smrg
155c9710b42Smrg#if HAVE_MKOSTEMP
156c9710b42Smrg    fd = mkostemp (template, FC_O_CLOEXEC);
157c9710b42Smrg#elif HAVE_MKSTEMP
158c9710b42Smrg    fd = mkstemp (template);
159c9710b42Smrg#  ifdef F_DUPFD_CLOEXEC
160c9710b42Smrg    if (fd != -1)
161c9710b42Smrg    {
162c9710b42Smrg	int newfd = fcntl(fd, F_DUPFD_CLOEXEC, STDIN_FILENO);
163c9710b42Smrg
164c9710b42Smrg	close(fd);
165c9710b42Smrg	fd = newfd;
166c9710b42Smrg    }
167c9710b42Smrg#  elif defined(FD_CLOEXEC)
168c9710b42Smrg    if (fd != -1)
169c9710b42Smrg    {
170c9710b42Smrg	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
171c9710b42Smrg    }
172c9710b42Smrg#  endif
173c9710b42Smrg#elif HAVE__MKTEMP_S
174c9710b42Smrg   if (_mktemp_s(template, strlen(template) + 1) != 0)
175c9710b42Smrg       return -1;
176c9710b42Smrg   fd = FcOpen(template, O_RDWR | O_EXCL | O_CREAT, 0600);
177c9710b42Smrg#endif
178c9710b42Smrg
179c9710b42Smrg    return fd;
180c9710b42Smrg}
181c9710b42Smrg
182c9710b42Smrgint32_t
183c9710b42SmrgFcRandom(void)
184c9710b42Smrg{
185c9710b42Smrg    int32_t result;
186c9710b42Smrg
187c9710b42Smrg#if HAVE_RANDOM_R
188c9710b42Smrg    static struct random_data fcrandbuf;
189c9710b42Smrg    static char statebuf[256];
190c9710b42Smrg    static FcBool initialized = FcFalse;
191b09479dcSmrg#ifdef _AIX
192b09479dcSmrg    static char *retval;
193b09479dcSmrg    long res;
194b09479dcSmrg#endif
195c9710b42Smrg
196c9710b42Smrg    if (initialized != FcTrue)
197c9710b42Smrg    {
198b09479dcSmrg#ifdef _AIX
199b09479dcSmrg	initstate_r (time (NULL), statebuf, 256, &retval, &fcrandbuf);
200b09479dcSmrg#else
201b09479dcSmrg	initstate_r (time (NULL), statebuf, 256, &fcrandbuf);
202b09479dcSmrg#endif
203c9710b42Smrg	initialized = FcTrue;
204c9710b42Smrg    }
205c9710b42Smrg
206b09479dcSmrg#ifdef _AIX
207b09479dcSmrg    random_r (&res, &fcrandbuf);
208b09479dcSmrg    result = (int32_t)res;
209b09479dcSmrg#else
210b09479dcSmrg    random_r (&fcrandbuf, &result);
211b09479dcSmrg#endif
212c9710b42Smrg#elif HAVE_RANDOM
213c9710b42Smrg    static char statebuf[256];
214c9710b42Smrg    char *state;
215c9710b42Smrg    static FcBool initialized = FcFalse;
216c9710b42Smrg
217c9710b42Smrg    if (initialized != FcTrue)
218c9710b42Smrg    {
219b09479dcSmrg	state = initstate (time (NULL), statebuf, 256);
220c9710b42Smrg	initialized = FcTrue;
221c9710b42Smrg    }
222c9710b42Smrg    else
223b09479dcSmrg	state = setstate (statebuf);
224c9710b42Smrg
225b09479dcSmrg    result = random ();
226c9710b42Smrg
227b09479dcSmrg    setstate (state);
228c9710b42Smrg#elif HAVE_LRAND48
229b09479dcSmrg    result = lrand48 ();
230c9710b42Smrg#elif HAVE_RAND_R
231ae02b298Smrg    static unsigned int seed;
232c9710b42Smrg
233ae02b298Smrg    seed = time (NULL);
234b09479dcSmrg    result = rand_r (&seed);
235c9710b42Smrg#elif HAVE_RAND
236c9710b42Smrg    static FcBool initialized = FcFalse;
237c9710b42Smrg
238c9710b42Smrg    if (initialized != FcTrue)
239c9710b42Smrg    {
240b09479dcSmrg	srand (time (NULL));
241c9710b42Smrg	initialized = FcTrue;
242c9710b42Smrg    }
243b09479dcSmrg    result = rand ();
244c9710b42Smrg#else
245c9710b42Smrg# error no random number generator function available.
246c9710b42Smrg#endif
247c9710b42Smrg
248c9710b42Smrg    return result;
249c9710b42Smrg}
2506fc018e4Smrg
2516fc018e4Smrg#ifdef _WIN32
2526fc018e4Smrg#include <direct.h>
2536fc018e4Smrg#define mkdir(path,mode) _mkdir(path)
2546fc018e4Smrg#endif
2556fc018e4Smrg
2566fc018e4SmrgFcBool
2576fc018e4SmrgFcMakeDirectory (const FcChar8 *dir)
2586fc018e4Smrg{
2596fc018e4Smrg    FcChar8 *parent;
2606fc018e4Smrg    FcBool  ret;
2616fc018e4Smrg
2626fc018e4Smrg    if (strlen ((char *) dir) == 0)
2636fc018e4Smrg	return FcFalse;
2646fc018e4Smrg
2656fc018e4Smrg    parent = FcStrDirname (dir);
2666fc018e4Smrg    if (!parent)
2676fc018e4Smrg	return FcFalse;
2686fc018e4Smrg    if (access ((char *) parent, F_OK) == 0)
2696fc018e4Smrg	ret = mkdir ((char *) dir, 0755) == 0 && chmod ((char *) dir, 0755) == 0;
2706fc018e4Smrg    else if (access ((char *) parent, F_OK) == -1)
2716fc018e4Smrg	ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0755) == 0) && chmod ((char *) dir, 0755) == 0;
2726fc018e4Smrg    else
2736fc018e4Smrg	ret = FcFalse;
2746fc018e4Smrg    FcStrFree (parent);
2756fc018e4Smrg    return ret;
2766fc018e4Smrg}
277953daebaSmrg
278a32e9e42Smrgssize_t
279a32e9e42SmrgFcReadLink (const FcChar8 *pathname,
280a32e9e42Smrg	    FcChar8       *buf,
281a32e9e42Smrg	    size_t         bufsiz)
282a32e9e42Smrg{
283a32e9e42Smrg#ifdef HAVE_READLINK
284a32e9e42Smrg    return readlink ((const char *) pathname, (char *)buf, bufsiz);
285a32e9e42Smrg#else
286a32e9e42Smrg    /* XXX: this function is only used for FcConfigRealFilename() so far
287a32e9e42Smrg     * and returning -1 as an error still just works.
288a32e9e42Smrg     */
289a32e9e42Smrg    errno = ENOSYS;
290a32e9e42Smrg    return -1;
291a32e9e42Smrg#endif
292a32e9e42Smrg}
293a32e9e42Smrg
294a4e54154Smrg/* On Windows MingW provides dirent.h / openddir(), but MSVC does not */
295a4e54154Smrg#ifndef HAVE_DIRENT_H
296a4e54154Smrg
297a4e54154Smrgstruct DIR {
298a4e54154Smrg    struct dirent d_ent;
299a4e54154Smrg    HANDLE handle;
300a4e54154Smrg    WIN32_FIND_DATA fdata;
301a4e54154Smrg    FcBool valid;
302a4e54154Smrg};
303a4e54154Smrg
304a4e54154SmrgFcPrivate DIR *
305a4e54154SmrgFcCompatOpendirWin32 (const char *dirname)
306a4e54154Smrg{
307a4e54154Smrg    size_t len;
308a4e54154Smrg    char *name;
309a4e54154Smrg    DIR *dir;
310a4e54154Smrg
311a4e54154Smrg    dir = calloc (1, sizeof (struct DIR));
312a4e54154Smrg    if (dir == NULL)
313a4e54154Smrg        return NULL;
314a4e54154Smrg
315a4e54154Smrg    len = strlen (dirname);
316a4e54154Smrg    name = malloc (len + 3);
317a4e54154Smrg    if (name == NULL)
318a4e54154Smrg    {
319a4e54154Smrg      free (dir);
320a4e54154Smrg      return NULL;
321a4e54154Smrg    }
322a4e54154Smrg    memcpy (name, dirname, len);
323a4e54154Smrg    name[len++] = FC_DIR_SEPARATOR;
324a4e54154Smrg    name[len++] = '*';
325a4e54154Smrg    name[len] = '\0';
326a4e54154Smrg
327a4e54154Smrg    dir->handle = FindFirstFileEx (name, FindExInfoBasic, &dir->fdata, FindExSearchNameMatch, NULL, 0);
328a4e54154Smrg
329a4e54154Smrg    free (name);
330a4e54154Smrg
331a4e54154Smrg    if (!dir->handle)
332a4e54154Smrg    {
333a4e54154Smrg        free (dir);
334a4e54154Smrg        dir = NULL;
335a4e54154Smrg
336a4e54154Smrg        if (GetLastError () == ERROR_FILE_NOT_FOUND)
337a4e54154Smrg            errno = ENOENT;
338a4e54154Smrg        else
339a4e54154Smrg            errno = EACCES;
340a4e54154Smrg    }
341a4e54154Smrg
342a4e54154Smrg    dir->valid = FcTrue;
343a4e54154Smrg    return dir;
344a4e54154Smrg}
345a4e54154Smrg
346a4e54154SmrgFcPrivate struct dirent *
347a4e54154SmrgFcCompatReaddirWin32 (DIR *dir)
348a4e54154Smrg{
349a4e54154Smrg    if (dir->valid != FcTrue)
350a4e54154Smrg        return NULL;
351a4e54154Smrg
352a4e54154Smrg    dir->d_ent.d_name = dir->fdata.cFileName;
353a4e54154Smrg
354a4e54154Smrg    if ((dir->fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
355a4e54154Smrg        dir->d_ent.d_type = DT_DIR;
356a4e54154Smrg    else if (dir->fdata.dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
357a4e54154Smrg        dir->d_ent.d_type = DT_REG;
358a4e54154Smrg    else
359a4e54154Smrg        dir->d_ent.d_type = DT_UNKNOWN;
360a4e54154Smrg
361a4e54154Smrg    if (!FindNextFile (dir->handle, &dir->fdata))
362a4e54154Smrg        dir->valid = FcFalse;
363a4e54154Smrg
364a4e54154Smrg    return &dir->d_ent;
365a4e54154Smrg}
366a4e54154Smrg
367a4e54154SmrgFcPrivate int
368a4e54154SmrgFcCompatClosedirWin32 (DIR *dir)
369a4e54154Smrg{
370a4e54154Smrg    if (dir != NULL && dir->handle != NULL)
371a4e54154Smrg    {
372a4e54154Smrg        FindClose (dir->handle);
373a4e54154Smrg        free (dir);
374a4e54154Smrg    }
375a4e54154Smrg    return 0;
376a4e54154Smrg}
377a4e54154Smrg#endif /* HAVE_DIRENT_H */
378a4e54154Smrg
379953daebaSmrg#define __fccompat__
380953daebaSmrg#include "fcaliastail.h"
381953daebaSmrg#undef __fccompat__
382