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 
54 int
setenv(const char * name,const char * value,int o)55 setenv(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 
68 extern FcChar8 *FcConfigRealFilename (FcConfig *, FcChar8 *);
69 extern FcChar8 *FcStrCanonFilename (const FcChar8 *);
70 
71 #ifdef HAVE_MKDTEMP
72 #define fc_mkdtemp	mkdtemp
73 #else
74 char *
fc_mkdtemp(char * template)75 fc_mkdtemp (char *template)
76 {
77     if (!mktemp (template) || mkdir (template, 0700))
78 	return NULL;
79 
80     return template;
81 }
82 #endif
83 
84 FcBool
mkdir_p(const char * dir)85 mkdir_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 
106 FcBool
unlink_dirs(const char * dir)107 unlink_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 
181 char template[512] = "/tmp/fc-d1f48f11-XXXXXX";
182 char systempl[512] = "/tmp/fc-d1f48f11-XXXXXX";
183 char *rootdir, *sysroot;
184 
185 int
setup(char * dir)186 setup (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;
216 bail:
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 
229 void
teardown(const char * dir)230 teardown (const char *dir)
231 {
232     unlink_dirs (dir);
233 }
234 
235 int
main(void)236 main (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;
286 bail:
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