1/*
2 * fontconfig/test/test-issue110.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 *);
69
70#ifdef HAVE_MKDTEMP
71#define fc_mkdtemp	mkdtemp
72#else
73char *
74fc_mkdtemp (char *template)
75{
76    if (!mktemp (template) || mkdir (template, 0700))
77	return NULL;
78
79    return template;
80}
81#endif
82
83FcBool
84mkdir_p (const char *dir)
85{
86    char *parent;
87    FcBool ret;
88
89    if (strlen (dir) == 0)
90	return FcFalse;
91    parent = (char *) FcStrDirname ((const FcChar8 *) dir);
92    if (!parent)
93	return FcFalse;
94    if (access (parent, F_OK) == 0)
95	ret = mkdir (dir, 0755) == 0 && chmod (dir, 0755) == 0;
96    else if (access (parent, F_OK) == -1)
97	ret = mkdir_p (parent) && (mkdir (dir, 0755) == 0) && chmod (dir, 0755) == 0;
98    else
99	ret = FcFalse;
100    free (parent);
101
102    return ret;
103}
104
105FcBool
106unlink_dirs (const char *dir)
107{
108    DIR *d = opendir (dir);
109    struct dirent *e;
110    size_t len = strlen (dir);
111    char *n = NULL;
112    FcBool ret = FcTrue;
113#ifndef HAVE_STRUCT_DIRENT_D_TYPE
114    struct stat statb;
115#endif
116
117    if (!d)
118	return FcFalse;
119    while ((e = readdir (d)) != NULL)
120    {
121	size_t l;
122
123	if (strcmp (e->d_name, ".") == 0 ||
124	    strcmp (e->d_name, "..") == 0)
125	    continue;
126	l = strlen (e->d_name) + 1;
127	if (n)
128	    free (n);
129	n = malloc (l + len + 1);
130	if (!n)
131	{
132	    ret = FcFalse;
133	    break;
134	}
135	strcpy (n, dir);
136	n[len] = FC_DIR_SEPARATOR;
137	strcpy (&n[len + 1], e->d_name);
138#ifdef HAVE_STRUCT_DIRENT_D_TYPE
139	if (e->d_type == DT_DIR)
140#else
141	if (stat (n, &statb) == -1)
142	{
143	    fprintf (stderr, "E: %s\n", n);
144	    ret = FcFalse;
145	    break;
146	}
147	if (S_ISDIR (statb.st_mode))
148#endif
149	{
150	    if (!unlink_dirs (n))
151	    {
152		fprintf (stderr, "E: %s\n", n);
153		ret = FcFalse;
154		break;
155	    }
156	}
157	else
158	{
159	    if (unlink (n) == -1)
160	    {
161		fprintf (stderr, "E: %s\n", n);
162		ret = FcFalse;
163		break;
164	    }
165	}
166    }
167    if (n)
168	free (n);
169    closedir (d);
170
171    if (rmdir (dir) == -1)
172    {
173	fprintf (stderr, "E: %s\n", dir);
174	return FcFalse;
175    }
176
177    return ret;
178}
179
180int
181main(void)
182{
183    FcConfig *cfg = FcConfigCreate ();
184    char *basedir, template[512] = "/tmp/fc110-XXXXXX";
185    char *sysroot, systempl[512] = "/tmp/fc110-XXXXXX";
186    FcChar8 *d = NULL;
187    FcChar8 *ret = NULL;
188    FcChar8 *s = NULL;
189    FILE *fp;
190    int retval = 0;
191
192    retval++;
193    basedir = fc_mkdtemp (template);
194    if (!basedir)
195    {
196	fprintf (stderr, "%s: %s\n", template, strerror (errno));
197	goto bail;
198    }
199    retval++;
200    sysroot = fc_mkdtemp (systempl);
201    if (!sysroot)
202    {
203	fprintf (stderr, "%s: %s\n", systempl, strerror (errno));
204	goto bail;
205    }
206    fprintf (stderr, "D: Creating %s\n", basedir);
207    mkdir_p (basedir);
208    setenv ("HOME", basedir, 1);
209    retval++;
210    s = FcStrBuildFilename (basedir, ".fonts.conf", NULL);
211    if (!s)
212	goto bail;
213    retval++;
214    fprintf (stderr, "D: Creating %s\n", s);
215    if ((fp = fopen (s, "wb")) == NULL)
216	goto bail;
217    fprintf (fp, "%s", s);
218    fclose (fp);
219    retval++;
220    fprintf (stderr, "D: Checking file path\n");
221    ret = FcConfigRealFilename (cfg, "~/.fonts.conf");
222    if (!ret)
223	goto bail;
224    retval++;
225    if (strcmp ((const char *) s, (const char *) ret) != 0)
226	goto bail;
227    free (ret);
228    free (s);
229    FcConfigDestroy (cfg);
230    setenv ("FONTCONFIG_SYSROOT", sysroot, 1);
231    cfg = FcConfigCreate ();
232    fprintf (stderr, "D: Creating %s\n", sysroot);
233    mkdir_p (sysroot);
234    retval++;
235    d = FcStrBuildFilename (sysroot, basedir, NULL);
236    fprintf (stderr, "D: Creating %s\n", d);
237    mkdir_p (d);
238    free (d);
239    s = FcStrBuildFilename (sysroot, basedir, ".fonts.conf", NULL);
240    if (!s)
241	goto bail;
242    retval++;
243    fprintf (stderr, "D: Creating %s\n", s);
244    if ((fp = fopen (s, "wb")) == NULL)
245	goto bail;
246    fprintf (fp, "%s", s);
247    fclose (fp);
248    retval++;
249    fprintf (stderr, "D: Checking file path\n");
250    ret = FcConfigRealFilename (cfg, "~/.fonts.conf");
251    if (!ret)
252	goto bail;
253    retval++;
254    if (strcmp ((const char *) s, (const char *) ret) != 0)
255	goto bail;
256    retval = 0;
257bail:
258    fprintf (stderr, "Cleaning up\n");
259    unlink_dirs (basedir);
260    if (ret)
261	free (ret);
262    if (s)
263	free (s);
264
265    return retval;
266}
267
268