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 86 typedef int mode_t; 87 #endif /* !HAVE_UNISTD_H */ 88 89 #if !defined (HAVE_MKOSTEMP) && !defined(HAVE_MKSTEMP) && !defined(HAVE__MKTEMP_S) 90 static int 91 mkstemp (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 126 int 127 FcOpen(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 150 int 151 FcMakeTempfile (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 182 int32_t 183 FcRandom(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 256 FcBool 257 FcMakeDirectory (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 278 ssize_t 279 FcReadLink (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 297 struct DIR { 298 struct dirent d_ent; 299 HANDLE handle; 300 WIN32_FIND_DATA fdata; 301 FcBool valid; 302 }; 303 304 FcPrivate DIR * 305 FcCompatOpendirWin32 (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 346 FcPrivate struct dirent * 347 FcCompatReaddirWin32 (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 367 FcPrivate int 368 FcCompatClosedirWin32 (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