(root)/
fontconfig-2.14.2/
src/
fcatomic.c
       1  /*
       2   * fontconfig/src/fcatomic.c
       3   *
       4   * Copyright © 2002 Keith Packard
       5   *
       6   * Permission to use, copy, modify, distribute, and sell this software and its
       7   * documentation for any purpose is hereby granted without fee, provided that
       8   * the above copyright notice appear in all copies and that both that
       9   * copyright notice and this permission notice appear in supporting
      10   * documentation, and that the name of the author(s) not be used in
      11   * advertising or publicity pertaining to distribution of the software without
      12   * specific, written prior permission.  The authors make no
      13   * representations about the suitability of this software for any purpose.  It
      14   * is provided "as is" without express or implied warranty.
      15   *
      16   * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
      17   * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
      18   * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
      19   * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
      20   * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
      21   * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      22   * PERFORMANCE OF THIS SOFTWARE.
      23   */
      24  
      25  /*
      26   * fcatomic.c
      27   *
      28   * Lock cache and configuration files for atomic update
      29   *
      30   * Uses only regular filesystem calls so it should
      31   * work even in the absense of functioning file locking
      32   *
      33   * On Unix, four files are used:
      34   *	file	    - the data file accessed by other apps.
      35   *	new	    - a new version of the data file while it's being written
      36   *	lck	    - the lock file
      37   *	tmp	    - a temporary file made unique with mkstemp
      38   *
      39   *  Here's how it works:
      40   *	Create 'tmp' and store our PID in it
      41   *	Attempt to link it to 'lck'
      42   *	Unlink 'tmp'
      43   *	If the link succeeded, the lock is held
      44   *
      45   * On Windows, where there are no links, no tmp file is used, and lck
      46   * is a directory that's mkdir'ed. If the mkdir succeeds, the lock is
      47   * held.
      48   */
      49  
      50  #ifdef HAVE_CONFIG_H
      51  #include <config.h>
      52  #endif
      53  
      54  #include "fcint.h"
      55  #include <sys/types.h>
      56  #include <sys/stat.h>
      57  #include <stdlib.h>
      58  #include <time.h>
      59  
      60  #ifdef HAVE_UNISTD_H
      61  #include <unistd.h>
      62  #endif
      63  
      64  #ifdef _WIN32
      65  #include <direct.h>
      66  #define mkdir(path,mode) _mkdir(path)
      67  #endif
      68  
      69  #define NEW_NAME	".NEW"
      70  #define LCK_NAME	".LCK"
      71  #define TMP_NAME	".TMP-XXXXXX"
      72  
      73  FcAtomic *
      74  FcAtomicCreate (const FcChar8   *file)
      75  {
      76      int	    file_len = strlen ((char *) file);
      77      int	    new_len = file_len + sizeof (NEW_NAME);
      78      int	    lck_len = file_len + sizeof (LCK_NAME);
      79      int	    tmp_len = file_len + sizeof (TMP_NAME);
      80      int	    total_len = (sizeof (FcAtomic) +
      81  			 file_len + 1 +
      82  			 new_len + 1 +
      83  			 lck_len + 1 +
      84  			 tmp_len + 1);
      85      FcAtomic	*atomic = malloc (total_len);
      86      if (!atomic)
      87  	return 0;
      88  
      89      atomic->file = (FcChar8 *) (atomic + 1);
      90      strcpy ((char *) atomic->file, (char *) file);
      91  
      92      atomic->new = atomic->file + file_len + 1;
      93      strcpy ((char *) atomic->new, (char *) file);
      94      strcat ((char *) atomic->new, NEW_NAME);
      95  
      96      atomic->lck = atomic->new + new_len + 1;
      97      strcpy ((char *) atomic->lck, (char *) file);
      98      strcat ((char *) atomic->lck, LCK_NAME);
      99  
     100      atomic->tmp = atomic->lck + lck_len + 1;
     101  
     102      return atomic;
     103  }
     104  
     105  FcBool
     106  FcAtomicLock (FcAtomic *atomic)
     107  {
     108      int		ret;
     109      struct stat	lck_stat;
     110  
     111  #ifdef HAVE_LINK
     112      int		fd = -1;
     113      FILE	*f = 0;
     114      FcBool	no_link = FcFalse;
     115  
     116      strcpy ((char *) atomic->tmp, (char *) atomic->file);
     117      strcat ((char *) atomic->tmp, TMP_NAME);
     118      fd = FcMakeTempfile ((char *) atomic->tmp);
     119      if (fd < 0)
     120  	return FcFalse;
     121      f = fdopen (fd, "w");
     122      if (!f)
     123      {
     124      	close (fd);
     125  	unlink ((char *) atomic->tmp);
     126  	return FcFalse;
     127      }
     128      ret = fprintf (f, "%ld\n", (long)getpid());
     129      if (ret <= 0)
     130      {
     131  	fclose (f);
     132  	unlink ((char *) atomic->tmp);
     133  	return FcFalse;
     134      }
     135      if (fclose (f) == EOF)
     136      {
     137  	unlink ((char *) atomic->tmp);
     138  	return FcFalse;
     139      }
     140      ret = link ((char *) atomic->tmp, (char *) atomic->lck);
     141      if (ret < 0 && (errno == EPERM || errno == ENOTSUP || errno == EACCES))
     142      {
     143  	/* the filesystem where atomic->lck points to may not supports
     144  	 * the hard link. so better try to fallback
     145  	 */
     146  	ret = mkdir ((char *) atomic->lck, 0600);
     147  	no_link = FcTrue;
     148      }
     149      (void) unlink ((char *) atomic->tmp);
     150  #else
     151      ret = mkdir ((char *) atomic->lck, 0600);
     152  #endif
     153      if (ret < 0)
     154      {
     155  	/*
     156  	 * If the file is around and old (> 10 minutes),
     157  	 * assume the lock is stale.  This assumes that any
     158  	 * machines sharing the same filesystem will have clocks
     159  	 * reasonably close to each other.
     160  	 */
     161  	if (FcStat (atomic->lck, &lck_stat) >= 0)
     162  	{
     163  	    time_t  now = time (0);
     164  	    if ((long int) (now - lck_stat.st_mtime) > 10 * 60)
     165  	    {
     166  #ifdef HAVE_LINK
     167  		if (no_link)
     168  		{
     169  		    if (rmdir ((char *) atomic->lck) == 0)
     170  			return FcAtomicLock (atomic);
     171  		}
     172  		else
     173  		{
     174  		    if (unlink ((char *) atomic->lck) == 0)
     175  			return FcAtomicLock (atomic);
     176  		}
     177  #else
     178  		if (rmdir ((char *) atomic->lck) == 0)
     179  		    return FcAtomicLock (atomic);
     180  #endif
     181  	    }
     182  	}
     183  	return FcFalse;
     184      }
     185      (void) unlink ((char *) atomic->new);
     186      return FcTrue;
     187  }
     188  
     189  FcChar8 *
     190  FcAtomicNewFile (FcAtomic *atomic)
     191  {
     192      return atomic->new;
     193  }
     194  
     195  FcChar8 *
     196  FcAtomicOrigFile (FcAtomic *atomic)
     197  {
     198      return atomic->file;
     199  }
     200  
     201  FcBool
     202  FcAtomicReplaceOrig (FcAtomic *atomic)
     203  {
     204  #ifdef _WIN32
     205      unlink ((const char *) atomic->file);
     206  #endif
     207      if (rename ((char *) atomic->new, (char *) atomic->file) < 0)
     208  	return FcFalse;
     209      return FcTrue;
     210  }
     211  
     212  void
     213  FcAtomicDeleteNew (FcAtomic *atomic)
     214  {
     215      unlink ((char *) atomic->new);
     216  }
     217  
     218  void
     219  FcAtomicUnlock (FcAtomic *atomic)
     220  {
     221  #ifdef HAVE_LINK
     222      if (unlink ((char *) atomic->lck) == -1)
     223  	rmdir ((char *) atomic->lck);
     224  #else
     225      rmdir ((char *) atomic->lck);
     226  #endif
     227  }
     228  
     229  void
     230  FcAtomicDestroy (FcAtomic *atomic)
     231  {
     232      if (atomic)
     233  	free (atomic);
     234  }
     235  #define __fcatomic__
     236  #include "fcaliastail.h"
     237  #undef __fcatomic__