test-d1f48f11.c revision a4e54154
1/*
2 * fontconfig/test/test-d1f48f11.c
3 *
4 * Copyright © 2000 Keith Packard
5 * Copyright © 2018 Akira TAGOH
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of the author(s) not be used in
12 * advertising or publicity pertaining to distribution of the software without
13 * specific, written prior permission.  The authors make no
14 * representations about the suitability of this software for any purpose.  It
15 * is provided "as is" without express or implied warranty.
16 *
17 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23 * PERFORMANCE OF THIS SOFTWARE.
24 */
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <dirent.h>
32#include <errno.h>
33#ifdef HAVE_UNISTD_H
34#include <unistd.h>
35#endif
36#ifndef HAVE_STRUCT_DIRENT_D_TYPE
37#include <sys/types.h>
38#include <sys/stat.h>
39#endif
40#include <fontconfig/fontconfig.h>
41
42#ifdef _WIN32
43#  define FC_DIR_SEPARATOR         '\\'
44#  define FC_DIR_SEPARATOR_S       "\\"
45#else
46#  define FC_DIR_SEPARATOR         '/'
47#  define FC_DIR_SEPARATOR_S       "/"
48#endif
49
50#ifdef _WIN32
51#include <direct.h>
52#define mkdir(path,mode) _mkdir(path)
53
54int
55setenv(const char *name, const char *value, int o)
56{
57    size_t len = strlen(name) + strlen(value) + 1;
58    char *s = malloc(len+1);
59    int ret;
60
61    snprintf(s, len, "%s=%s", name, value);
62    ret = _putenv(s);
63    free(s);
64    return ret;
65}
66#endif
67
68extern FcChar8 *FcConfigRealFilename (FcConfig *, FcChar8 *);
69extern FcChar8 *FcStrCanonFilename (const FcChar8 *);
70
71#ifdef HAVE_MKDTEMP
72#define fc_mkdtemp	mkdtemp
73#else
74char *
75fc_mkdtemp (char *template)
76{
77    if (!mktemp (template) || mkdir (template, 0700))
78	return NULL;
79
80    return template;
81}
82#endif
83
84FcBool
85mkdir_p (const char *dir)
86{
87    char *parent;
88    FcBool ret;
89
90    if (strlen (dir) == 0)
91	return FcFalse;
92    parent = (char *) FcStrDirname ((const FcChar8 *) dir);
93    if (!parent)
94	return FcFalse;
95    if (access (parent, F_OK) == 0)
96	ret = mkdir (dir, 0755) == 0 && chmod (dir, 0755) == 0;
97    else if (access (parent, F_OK) == -1)
98	ret = mkdir_p (parent) && (mkdir (dir, 0755) == 0) && chmod (dir, 0755) == 0;
99    else
100	ret = FcFalse;
101    free (parent);
102
103    return ret;
104}
105
106FcBool
107unlink_dirs (const char *dir)
108{
109    DIR *d = opendir (dir);
110    struct dirent *e;
111    size_t len = strlen (dir);
112    char *n = NULL;
113    FcBool ret = FcTrue;
114#ifndef HAVE_STRUCT_DIRENT_D_TYPE
115    struct stat statb;
116#endif
117
118    if (!d)
119	return FcFalse;
120    while ((e = readdir (d)) != NULL)
121    {
122	size_t l;
123
124	if (strcmp (e->d_name, ".") == 0 ||
125	    strcmp (e->d_name, "..") == 0)
126	    continue;
127	l = strlen (e->d_name) + 1;
128	if (n)
129	    free (n);
130	n = malloc (l + len + 1);
131	if (!n)
132	{
133	    ret = FcFalse;
134	    break;
135	}
136	strcpy (n, dir);
137	n[len] = FC_DIR_SEPARATOR;
138	strcpy (&n[len + 1], e->d_name);
139#ifdef HAVE_STRUCT_DIRENT_D_TYPE
140	if (e->d_type == DT_DIR)
141#else
142	if (stat (n, &statb) == -1)
143	{
144	    fprintf (stderr, "E: %s\n", n);
145	    ret = FcFalse;
146	    break;
147	}
148	if (S_ISDIR (statb.st_mode))
149#endif
150	{
151	    if (!unlink_dirs (n))
152	    {
153		fprintf (stderr, "E: %s\n", n);
154		ret = FcFalse;
155		break;
156	    }
157	}
158	else
159	{
160	    if (unlink (n) == -1)
161	    {
162		fprintf (stderr, "E: %s\n", n);
163		ret = FcFalse;
164		break;
165	    }
166	}
167    }
168    if (n)
169	free (n);
170    closedir (d);
171
172    if (rmdir (dir) == -1)
173    {
174	fprintf (stderr, "E: %s\n", dir);
175	return FcFalse;
176    }
177
178    return ret;
179}
180
181char template[512] = "/tmp/fc-d1f48f11-XXXXXX";
182char systempl[512] = "/tmp/fc-d1f48f11-XXXXXX";
183char *rootdir, *sysroot;
184
185int
186setup (char *dir)
187{
188    FcChar8 *confdir = NULL, *availdir = NULL, *real = NULL, *link = NULL;
189    FILE *fp;
190    int ret = 1;
191
192    confdir = FcStrBuildFilename (dir, "conf.d", NULL);
193    availdir = FcStrBuildFilename (dir, "conf.avail", NULL);
194    mkdir_p (confdir);
195    mkdir_p (availdir);
196    real = FcStrBuildFilename (availdir, "00-foo.conf", NULL);
197    link = FcStrBuildFilename (confdir, "00-foo.conf", NULL);
198    if (!real || !link)
199    {
200	fprintf (stderr, "E: unable to allocate memory\n");
201	goto bail;
202    }
203    if ((fp = fopen (real, "wb")) == NULL)
204    {
205	fprintf (stderr, "E: unable to open a file\n");
206	goto bail;
207    }
208    fprintf (fp, "%s", real);
209    fclose (fp);
210    if (symlink ("../conf.avail/00-foo.conf", link) != 0)
211    {
212	fprintf (stderr, "%s: %s\n", link, strerror (errno));
213	goto bail;
214    }
215    ret = 0;
216bail:
217    if (real)
218	free (real);
219    if (link)
220	free (link);
221    if (availdir)
222	free (availdir);
223    if (confdir)
224	free (confdir);
225
226    return ret;
227}
228
229void
230teardown (const char *dir)
231{
232    unlink_dirs (dir);
233}
234
235int
236main (void)
237{
238    FcConfig *cfg = NULL;
239    FcChar8 *dc = NULL, *da = NULL, *d = NULL;
240    FcChar8 *ds = NULL, *dsa = NULL, *dsac = NULL;
241    int ret = 1;
242
243    rootdir = fc_mkdtemp (template);
244    if (!rootdir)
245    {
246	fprintf (stderr, "%s: %s\n", template, strerror (errno));
247	return 1;
248    }
249    sysroot = fc_mkdtemp (systempl);
250    if (!sysroot)
251    {
252	fprintf (stderr, "%s: %s\n", systempl, strerror (errno));
253	return 1;
254    }
255    ds = FcStrBuildFilename (sysroot, rootdir, NULL);
256
257    if (setup (rootdir) != 0)
258	goto bail;
259    if (setup (ds) != 0)
260	goto bail;
261
262    dc = FcStrBuildFilename (rootdir, "conf.d", "00-foo.conf", NULL);
263    da = FcStrBuildFilename (rootdir, "conf.avail", "00-foo.conf", NULL);
264    cfg = FcConfigCreate ();
265    d = FcConfigRealFilename (cfg, dc);
266    if (strcmp ((const char *)d, (const char *)da) != 0)
267    {
268	fprintf (stderr, "E: failed to compare for non-sysroot: %s, %s\n", d, da);
269	goto bail;
270    }
271
272    free (d);
273    FcConfigDestroy (cfg);
274    setenv ("FONTCONFIG_SYSROOT", sysroot, 1);
275    cfg = FcConfigCreate ();
276    dsa = FcStrBuildFilename (sysroot, da, NULL);
277    dsac = FcStrCanonFilename (dsa);
278    d = FcConfigRealFilename (cfg, dc);
279    if (strcmp ((const char *)d, (const char *)dsac) != 0)
280    {
281	fprintf (stderr, "E: failed to compare for sysroot: %s, %s\n", d, dsac);
282	goto bail;
283    }
284
285    ret = 0;
286bail:
287    if (cfg)
288	FcConfigDestroy (cfg);
289    if (ds)
290	free (ds);
291    if (dsa)
292	free (dsa);
293    if (dsac)
294	free (dsac);
295    if (dc)
296	free (dc);
297    if (da)
298	free (da);
299    if (d)
300	free (d);
301    teardown (sysroot);
302    teardown (rootdir);
303
304    return ret;
305}
306