fcatomic.c revision 2c393a42
12c393a42Smrg/*
22c393a42Smrg * $RCSId: xc/lib/fontconfig/src/fcatomic.c,v 1.2 2002/03/04 21:15:28 tsi Exp $
32c393a42Smrg *
42c393a42Smrg * Copyright © 2002 Keith Packard
52c393a42Smrg *
62c393a42Smrg * Permission to use, copy, modify, distribute, and sell this software and its
72c393a42Smrg * documentation for any purpose is hereby granted without fee, provided that
82c393a42Smrg * the above copyright notice appear in all copies and that both that
92c393a42Smrg * copyright notice and this permission notice appear in supporting
102c393a42Smrg * documentation, and that the name of Keith Packard not be used in
112c393a42Smrg * advertising or publicity pertaining to distribution of the software without
122c393a42Smrg * specific, written prior permission.  Keith Packard makes no
132c393a42Smrg * representations about the suitability of this software for any purpose.  It
142c393a42Smrg * is provided "as is" without express or implied warranty.
152c393a42Smrg *
162c393a42Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
182c393a42Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
192c393a42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
202c393a42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
212c393a42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
222c393a42Smrg * PERFORMANCE OF THIS SOFTWARE.
232c393a42Smrg */
242c393a42Smrg
252c393a42Smrg/*
262c393a42Smrg * fcatomic.c
272c393a42Smrg *
282c393a42Smrg * Lock cache and configuration files for atomic update
292c393a42Smrg *
302c393a42Smrg * Uses only regular filesystem calls so it should
312c393a42Smrg * work even in the absense of functioning file locking
322c393a42Smrg *
332c393a42Smrg * On Unix, four files are used:
342c393a42Smrg *	file	    - the data file accessed by other apps.
352c393a42Smrg *	new	    - a new version of the data file while it's being written
362c393a42Smrg *	lck	    - the lock file
372c393a42Smrg *	tmp	    - a temporary file made unique with mkstemp
382c393a42Smrg *
392c393a42Smrg *  Here's how it works:
402c393a42Smrg *	Create 'tmp' and store our PID in it
412c393a42Smrg *	Attempt to link it to 'lck'
422c393a42Smrg *	Unlink 'tmp'
432c393a42Smrg *	If the link succeeded, the lock is held
442c393a42Smrg *
452c393a42Smrg * On Windows, where there are no links, no tmp file is used, and lck
462c393a42Smrg * is a directory that's mkdir'ed. If the mkdir succeeds, the lock is
472c393a42Smrg * held.
482c393a42Smrg */
492c393a42Smrg
502c393a42Smrg#include "fcint.h"
512c393a42Smrg#include <sys/types.h>
522c393a42Smrg#include <sys/stat.h>
532c393a42Smrg#include <fcntl.h>
542c393a42Smrg#include <unistd.h>
552c393a42Smrg#include <stdlib.h>
562c393a42Smrg#include <time.h>
572c393a42Smrg
582c393a42Smrg#ifdef _WIN32
592c393a42Smrg#define mkdir(path,mode) _mkdir(path)
602c393a42Smrg#endif
612c393a42Smrg
622c393a42Smrg#define NEW_NAME	".NEW"
632c393a42Smrg#define LCK_NAME	".LCK"
642c393a42Smrg#define TMP_NAME	".TMP-XXXXXX"
652c393a42Smrg
662c393a42SmrgFcAtomic *
672c393a42SmrgFcAtomicCreate (const FcChar8   *file)
682c393a42Smrg{
692c393a42Smrg    int	    file_len = strlen ((char *) file);
702c393a42Smrg    int	    new_len = file_len + sizeof (NEW_NAME);
712c393a42Smrg    int	    lck_len = file_len + sizeof (LCK_NAME);
722c393a42Smrg    int	    tmp_len = file_len + sizeof (TMP_NAME);
732c393a42Smrg    int	    total_len = (sizeof (FcAtomic) +
742c393a42Smrg			 file_len + 1 +
752c393a42Smrg			 new_len + 1 +
762c393a42Smrg			 lck_len + 1 +
772c393a42Smrg			 tmp_len + 1);
782c393a42Smrg    FcAtomic	*atomic = malloc (total_len);
792c393a42Smrg    if (!atomic)
802c393a42Smrg	return 0;
812c393a42Smrg    FcMemAlloc (FC_MEM_ATOMIC, total_len);
822c393a42Smrg
832c393a42Smrg    atomic->file = (FcChar8 *) (atomic + 1);
842c393a42Smrg    strcpy ((char *) atomic->file, (char *) file);
852c393a42Smrg
862c393a42Smrg    atomic->new = atomic->file + file_len + 1;
872c393a42Smrg    strcpy ((char *) atomic->new, (char *) file);
882c393a42Smrg    strcat ((char *) atomic->new, NEW_NAME);
892c393a42Smrg
902c393a42Smrg    atomic->lck = atomic->new + new_len + 1;
912c393a42Smrg    strcpy ((char *) atomic->lck, (char *) file);
922c393a42Smrg    strcat ((char *) atomic->lck, LCK_NAME);
932c393a42Smrg
942c393a42Smrg    atomic->tmp = atomic->lck + lck_len + 1;
952c393a42Smrg
962c393a42Smrg    return atomic;
972c393a42Smrg}
982c393a42Smrg
992c393a42SmrgFcBool
1002c393a42SmrgFcAtomicLock (FcAtomic *atomic)
1012c393a42Smrg{
1022c393a42Smrg    int		fd = -1;
1032c393a42Smrg    FILE	*f = 0;
1042c393a42Smrg    int		ret;
1052c393a42Smrg    struct stat	lck_stat;
1062c393a42Smrg
1072c393a42Smrg#ifdef HAVE_LINK
1082c393a42Smrg    strcpy ((char *) atomic->tmp, (char *) atomic->file);
1092c393a42Smrg    strcat ((char *) atomic->tmp, TMP_NAME);
1102c393a42Smrg    fd = mkstemp ((char *) atomic->tmp);
1112c393a42Smrg    if (fd < 0)
1122c393a42Smrg	return FcFalse;
1132c393a42Smrg    f = fdopen (fd, "w");
1142c393a42Smrg    if (!f)
1152c393a42Smrg    {
1162c393a42Smrg    	close (fd);
1172c393a42Smrg	unlink ((char *) atomic->tmp);
1182c393a42Smrg	return FcFalse;
1192c393a42Smrg    }
1202c393a42Smrg    ret = fprintf (f, "%ld\n", (long)getpid());
1212c393a42Smrg    if (ret <= 0)
1222c393a42Smrg    {
1232c393a42Smrg	fclose (f);
1242c393a42Smrg	unlink ((char *) atomic->tmp);
1252c393a42Smrg	return FcFalse;
1262c393a42Smrg    }
1272c393a42Smrg    if (fclose (f) == EOF)
1282c393a42Smrg    {
1292c393a42Smrg	unlink ((char *) atomic->tmp);
1302c393a42Smrg	return FcFalse;
1312c393a42Smrg    }
1322c393a42Smrg    ret = link ((char *) atomic->tmp, (char *) atomic->lck);
1332c393a42Smrg    (void) unlink ((char *) atomic->tmp);
1342c393a42Smrg#else
1352c393a42Smrg    ret = mkdir ((char *) atomic->lck, 0600);
1362c393a42Smrg#endif
1372c393a42Smrg    if (ret < 0)
1382c393a42Smrg    {
1392c393a42Smrg	/*
1402c393a42Smrg	 * If the file is around and old (> 10 minutes),
1412c393a42Smrg	 * assume the lock is stale.  This assumes that any
1422c393a42Smrg	 * machines sharing the same filesystem will have clocks
1432c393a42Smrg	 * reasonably close to each other.
1442c393a42Smrg	 */
1452c393a42Smrg	if (stat ((char *) atomic->lck, &lck_stat) >= 0)
1462c393a42Smrg	{
1472c393a42Smrg	    time_t  now = time (0);
1482c393a42Smrg	    if ((long int) (now - lck_stat.st_mtime) > 10 * 60)
1492c393a42Smrg	    {
1502c393a42Smrg#ifdef HAVE_LINK
1512c393a42Smrg		if (unlink ((char *) atomic->lck) == 0)
1522c393a42Smrg		    return FcAtomicLock (atomic);
1532c393a42Smrg#else
1542c393a42Smrg		if (rmdir ((char *) atomic->lck) == 0)
1552c393a42Smrg		    return FcAtomicLock (atomic);
1562c393a42Smrg#endif
1572c393a42Smrg	    }
1582c393a42Smrg	}
1592c393a42Smrg	return FcFalse;
1602c393a42Smrg    }
1612c393a42Smrg    (void) unlink ((char *) atomic->new);
1622c393a42Smrg    return FcTrue;
1632c393a42Smrg}
1642c393a42Smrg
1652c393a42SmrgFcChar8 *
1662c393a42SmrgFcAtomicNewFile (FcAtomic *atomic)
1672c393a42Smrg{
1682c393a42Smrg    return atomic->new;
1692c393a42Smrg}
1702c393a42Smrg
1712c393a42SmrgFcChar8 *
1722c393a42SmrgFcAtomicOrigFile (FcAtomic *atomic)
1732c393a42Smrg{
1742c393a42Smrg    return atomic->file;
1752c393a42Smrg}
1762c393a42Smrg
1772c393a42SmrgFcBool
1782c393a42SmrgFcAtomicReplaceOrig (FcAtomic *atomic)
1792c393a42Smrg{
1802c393a42Smrg#ifdef _WIN32
1812c393a42Smrg    unlink (atomic->file);
1822c393a42Smrg#endif
1832c393a42Smrg    if (rename ((char *) atomic->new, (char *) atomic->file) < 0)
1842c393a42Smrg	return FcFalse;
1852c393a42Smrg    return FcTrue;
1862c393a42Smrg}
1872c393a42Smrg
1882c393a42Smrgvoid
1892c393a42SmrgFcAtomicDeleteNew (FcAtomic *atomic)
1902c393a42Smrg{
1912c393a42Smrg    unlink ((char *) atomic->new);
1922c393a42Smrg}
1932c393a42Smrg
1942c393a42Smrgvoid
1952c393a42SmrgFcAtomicUnlock (FcAtomic *atomic)
1962c393a42Smrg{
1972c393a42Smrg#ifdef HAVE_LINK
1982c393a42Smrg    unlink ((char *) atomic->lck);
1992c393a42Smrg#else
2002c393a42Smrg    rmdir ((char *) atomic->lck);
2012c393a42Smrg#endif
2022c393a42Smrg}
2032c393a42Smrg
2042c393a42Smrgvoid
2052c393a42SmrgFcAtomicDestroy (FcAtomic *atomic)
2062c393a42Smrg{
2072c393a42Smrg    FcMemFree (FC_MEM_ATOMIC, sizeof (FcAtomic) +
2082c393a42Smrg	       strlen ((char *) atomic->file) * 4 + 4 +
2092c393a42Smrg	       sizeof (NEW_NAME) + sizeof (LCK_NAME) +
2102c393a42Smrg	       sizeof (TMP_NAME));
2112c393a42Smrg
2122c393a42Smrg    free (atomic);
2132c393a42Smrg}
2142c393a42Smrg#define __fcatomic__
2152c393a42Smrg#include "fcaliastail.h"
2162c393a42Smrg#undef __fcatomic__
217