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#if HAVE_UNISTD_H 41#include <unistd.h> 42#endif 43#include <stdarg.h> 44#include <stdlib.h> 45#include <string.h> 46#include <time.h> 47 48#ifdef O_CLOEXEC 49#define FC_O_CLOEXEC O_CLOEXEC 50#else 51#define FC_O_CLOEXEC 0 52#endif 53#ifdef O_LARGEFILE 54#define FC_O_LARGEFILE O_LARGEFILE 55#else 56#define FC_O_LARGEFILE 0 57#endif 58#ifdef O_BINARY 59#define FC_O_BINARY O_BINARY 60#else 61#define FC_O_BINARY 0 62#endif 63#ifdef O_TEMPORARY 64#define FC_O_TEMPORARY O_TEMPORARY 65#else 66#define FC_O_TEMPORARY 0 67#endif 68#ifdef O_NOINHERIT 69#define FC_O_NOINHERIT O_NOINHERIT 70#else 71#define FC_O_NOINHERIT 0 72#endif 73 74#ifndef HAVE_UNISTD_H 75/* Values for the second argument to access. These may be OR'd together. */ 76#ifndef R_OK 77#define R_OK 4 /* Test for read permission. */ 78#endif 79#ifndef W_OK 80#define W_OK 2 /* Test for write permission. */ 81#endif 82#ifndef F_OK 83#define F_OK 0 /* Test for existence. */ 84#endif 85 86typedef int mode_t; 87#endif /* !HAVE_UNISTD_H */ 88 89#if !defined (HAVE_MKOSTEMP) && !defined(HAVE_MKSTEMP) && !defined(HAVE__MKTEMP_S) 90static int 91mkstemp (char *template) 92{ 93 static const char s[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 94 int fd, i; 95 size_t l; 96 97 if (template == NULL) 98 { 99 errno = EINVAL; 100 return -1; 101 } 102 l = strlen (template); 103 if (l < 6 || strcmp (&template[l - 6], "XXXXXX") != 0) 104 { 105 errno = EINVAL; 106 return -1; 107 } 108 do 109 { 110 errno = 0; 111 for (i = l - 6; i < l; i++) 112 { 113 int r = FcRandom (); 114 template[i] = s[r % 62]; 115 } 116 fd = FcOpen (template, FC_O_BINARY | O_CREAT | O_EXCL | FC_O_TEMPORARY | FC_O_NOINHERIT | O_RDWR, 0600); 117 } while (fd < 0 && errno == EEXIST); 118 if (fd >= 0) 119 errno = 0; 120 121 return fd; 122} 123#define HAVE_MKSTEMP 1 124#endif 125 126int 127FcOpen(const char *pathname, int flags, ...) 128{ 129 int fd = -1; 130 131 if (flags & O_CREAT) 132 { 133 va_list ap; 134 mode_t mode; 135 136 va_start(ap, flags); 137 mode = (mode_t) va_arg(ap, int); 138 va_end(ap); 139 140 fd = open(pathname, flags | FC_O_CLOEXEC | FC_O_LARGEFILE, mode); 141 } 142 else 143 { 144 fd = open(pathname, flags | FC_O_CLOEXEC | FC_O_LARGEFILE); 145 } 146 147 return fd; 148} 149 150int 151FcMakeTempfile (char *template) 152{ 153 int fd = -1; 154 155#if HAVE_MKOSTEMP 156 fd = mkostemp (template, FC_O_CLOEXEC); 157#elif HAVE_MKSTEMP 158 fd = mkstemp (template); 159# ifdef F_DUPFD_CLOEXEC 160 if (fd != -1) 161 { 162 int newfd = fcntl(fd, F_DUPFD_CLOEXEC, STDIN_FILENO); 163 164 close(fd); 165 fd = newfd; 166 } 167# elif defined(FD_CLOEXEC) 168 if (fd != -1) 169 { 170 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 171 } 172# endif 173#elif HAVE__MKTEMP_S 174 if (_mktemp_s(template, strlen(template) + 1) != 0) 175 return -1; 176 fd = FcOpen(template, O_RDWR | O_EXCL | O_CREAT, 0600); 177#endif 178 179 return fd; 180} 181 182int32_t 183FcRandom(void) 184{ 185 int32_t result; 186 187#if HAVE_RANDOM_R 188 static struct random_data fcrandbuf; 189 static char statebuf[256]; 190 static FcBool initialized = FcFalse; 191#ifdef _AIX 192 static char *retval; 193 long res; 194#endif 195 196 if (initialized != FcTrue) 197 { 198#ifdef _AIX 199 initstate_r (time (NULL), statebuf, 256, &retval, &fcrandbuf); 200#else 201 initstate_r (time (NULL), statebuf, 256, &fcrandbuf); 202#endif 203 initialized = FcTrue; 204 } 205 206#ifdef _AIX 207 random_r (&res, &fcrandbuf); 208 result = (int32_t)res; 209#else 210 random_r (&fcrandbuf, &result); 211#endif 212#elif HAVE_RANDOM 213 static char statebuf[256]; 214 char *state; 215 static FcBool initialized = FcFalse; 216 217 if (initialized != FcTrue) 218 { 219 state = initstate (time (NULL), statebuf, 256); 220 initialized = FcTrue; 221 } 222 else 223 state = setstate (statebuf); 224 225 result = random (); 226 227 setstate (state); 228#elif HAVE_LRAND48 229 result = lrand48 (); 230#elif HAVE_RAND_R 231 static unsigned int seed; 232 233 seed = time (NULL); 234 result = rand_r (&seed); 235#elif HAVE_RAND 236 static FcBool initialized = FcFalse; 237 238 if (initialized != FcTrue) 239 { 240 srand (time (NULL)); 241 initialized = FcTrue; 242 } 243 result = rand (); 244#else 245# error no random number generator function available. 246#endif 247 248 return result; 249} 250 251#ifdef _WIN32 252#include <direct.h> 253#define mkdir(path,mode) _mkdir(path) 254#endif 255 256FcBool 257FcMakeDirectory (const FcChar8 *dir) 258{ 259 FcChar8 *parent; 260 FcBool ret; 261 262 if (strlen ((char *) dir) == 0) 263 return FcFalse; 264 265 parent = FcStrDirname (dir); 266 if (!parent) 267 return FcFalse; 268 if (access ((char *) parent, F_OK) == 0) 269 ret = mkdir ((char *) dir, 0755) == 0 && chmod ((char *) dir, 0755) == 0; 270 else if (access ((char *) parent, F_OK) == -1) 271 ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0755) == 0) && chmod ((char *) dir, 0755) == 0; 272 else 273 ret = FcFalse; 274 FcStrFree (parent); 275 return ret; 276} 277 278ssize_t 279FcReadLink (const FcChar8 *pathname, 280 FcChar8 *buf, 281 size_t bufsiz) 282{ 283#ifdef HAVE_READLINK 284 return readlink ((const char *) pathname, (char *)buf, bufsiz); 285#else 286 /* XXX: this function is only used for FcConfigRealFilename() so far 287 * and returning -1 as an error still just works. 288 */ 289 errno = ENOSYS; 290 return -1; 291#endif 292} 293 294/* On Windows MingW provides dirent.h / openddir(), but MSVC does not */ 295#ifndef HAVE_DIRENT_H 296 297struct DIR { 298 struct dirent d_ent; 299 HANDLE handle; 300 WIN32_FIND_DATA fdata; 301 FcBool valid; 302}; 303 304FcPrivate DIR * 305FcCompatOpendirWin32 (const char *dirname) 306{ 307 size_t len; 308 char *name; 309 DIR *dir; 310 311 dir = calloc (1, sizeof (struct DIR)); 312 if (dir == NULL) 313 return NULL; 314 315 len = strlen (dirname); 316 name = malloc (len + 3); 317 if (name == NULL) 318 { 319 free (dir); 320 return NULL; 321 } 322 memcpy (name, dirname, len); 323 name[len++] = FC_DIR_SEPARATOR; 324 name[len++] = '*'; 325 name[len] = '\0'; 326 327 dir->handle = FindFirstFileEx (name, FindExInfoBasic, &dir->fdata, FindExSearchNameMatch, NULL, 0); 328 329 free (name); 330 331 if (!dir->handle) 332 { 333 free (dir); 334 dir = NULL; 335 336 if (GetLastError () == ERROR_FILE_NOT_FOUND) 337 errno = ENOENT; 338 else 339 errno = EACCES; 340 } 341 342 dir->valid = FcTrue; 343 return dir; 344} 345 346FcPrivate struct dirent * 347FcCompatReaddirWin32 (DIR *dir) 348{ 349 if (dir->valid != FcTrue) 350 return NULL; 351 352 dir->d_ent.d_name = dir->fdata.cFileName; 353 354 if ((dir->fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) 355 dir->d_ent.d_type = DT_DIR; 356 else if (dir->fdata.dwFileAttributes == FILE_ATTRIBUTE_NORMAL) 357 dir->d_ent.d_type = DT_REG; 358 else 359 dir->d_ent.d_type = DT_UNKNOWN; 360 361 if (!FindNextFile (dir->handle, &dir->fdata)) 362 dir->valid = FcFalse; 363 364 return &dir->d_ent; 365} 366 367FcPrivate int 368FcCompatClosedirWin32 (DIR *dir) 369{ 370 if (dir != NULL && dir->handle != NULL) 371 { 372 FindClose (dir->handle); 373 free (dir); 374 } 375 return 0; 376} 377#endif /* HAVE_DIRENT_H */ 378 379#define __fccompat__ 380#include "fcaliastail.h" 381#undef __fccompat__ 382