Home | History | Annotate | Line # | Download | only in src
      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