Coda File System

Re: Gnucash lock problem on CODA

From: Anocha Yimsiriwattana <tawtao_at_tawtao.com>
Date: Mon, 23 Jun 2003 09:43:50 -0400
Hi Ivav,

> > Since Coda does not have any support for file locking, the problem is
> > understandable.  It is not really big problem because I still be able to
> > use GnuCash on Coda.  Just ignore the message.
> >
> > >     http://www.gnucash.org/docs/C/gnucash-guide/backup1.html
>
> If I interpret the documentation right, the locking GnuCash uses is
> file creation in exclusive mode.
>
> Though such operaton is not guaranteed to be exclusive on Coda,
> normally it will not fail, so GnuCash should be happy (and clean the
> "lock files" afterwards).
> Looking at the source or strace results would possibly give the answer,
> why you seem to observe that problem on Coda but not otherwise.

I did not means to be too offensive, but I did check in the GnuCash and does 
not assume it is only CODA problem.  I have download GnuCash and
take a look at the code.  The section of GnuCash code that does locking is 
attached at the end.  I agree with Ivan that GnuCash uses exclusive mode.

I plans to do something with it, but before doing so I need to what do you 
guys think about the problem it self.   Since CODA does not have support for 
file locking, which I refer to Jan, work around for CODA is needed.  If any 
one have any idea, please let me know.  I wll get back later.

Is it possible to implement locking mechanism in CODA?  I am a newbie to CODA 
code "hacking" :-P ... 

>
> My 2c,
> --
> Ivan

Thanks,

Anocha
========================================================
Code from $GNUCASH_SRC_DIR/src/backend/file/gnc-backend-file.c
------------------------------------------------------------------------------------

static gboolean
gnc_file_be_get_file_lock (FileBackend *be)
{
    struct stat statbuf;
    char pathbuf[PATH_MAX];
    char *path = NULL;
    int rc;

    rc = stat (be->lockfile, &statbuf);
    if (!rc)
    {
        /* oops .. file is all locked up  .. */
        xaccBackendSetError ((Backend*)be, ERR_BACKEND_LOCKED);
        return FALSE;
    }

    be->lockfd = open (be->lockfile, O_RDWR | O_CREAT | O_EXCL , 0);
    if (be->lockfd < 0)
    {
        /* oops .. file is all locked up  .. */
        xaccBackendSetError ((Backend*)be, ERR_BACKEND_LOCKED);
        return FALSE;
    }

    /* OK, now work around some NFS atomic lock race condition
     * mumbo-jumbo.  We do this by linking a unique file, and
     * then examing the link count.  At least that's what the
     * NFS programmers guide suggests.
     * Note: the "unique filename" must be unique for the
     * triplet filename-host-process, otherwise accidental
     * aliases can occur.
     */

    /* apparently, even this code may not work for some NFS
     * implementations. In the long run, I am told that
     * ftp.debian.org
     *  /pub/debian/dists/unstable/main/source/libs/liblockfile_0.1-6.tar.gz
     * provides a better long-term solution.
     */

    strcpy (pathbuf, be->lockfile);
    path = strrchr (pathbuf, '.');
    sprintf (path, ".%lx.%d.LNK", gethostid(), getpid());

    rc = link (be->lockfile, pathbuf);
    if (rc)
    {
static gboolean
gnc_file_be_get_file_lock (FileBackend *be)
{
    struct stat statbuf;
    char pathbuf[PATH_MAX];
    char *path = NULL;
    int rc;

    rc = stat (be->lockfile, &statbuf);
    if (!rc)
    {
        /* oops .. file is all locked up  .. */
        xaccBackendSetError ((Backend*)be, ERR_BACKEND_LOCKED);
        return FALSE;
    }

    be->lockfd = open (be->lockfile, O_RDWR | O_CREAT | O_EXCL , 0);
    if (be->lockfd < 0)
    {
        /* oops .. file is all locked up  .. */
        xaccBackendSetError ((Backend*)be, ERR_BACKEND_LOCKED);
        return FALSE;
    }

    /* OK, now work around some NFS atomic lock race condition
     * mumbo-jumbo.  We do this by linking a unique file, and
     * then examing the link count.  At least that's what the
     * NFS programmers guide suggests.
     * Note: the "unique filename" must be unique for the
     * triplet filename-host-process, otherwise accidental
     * aliases can occur.
     */

    /* apparently, even this code may not work for some NFS
     * implementations. In the long run, I am told that
     * ftp.debian.org
     *  /pub/debian/dists/unstable/main/source/libs/liblockfile_0.1-6.tar.gz
     * provides a better long-term solution.
     */

    strcpy (pathbuf, be->lockfile);
    path = strrchr (pathbuf, '.');
    sprintf (path, ".%lx.%d.LNK", gethostid(), getpid());

    rc = link (be->lockfile, pathbuf);
    if (rc)
    {
        /* If hard links aren't supported, just allow the lock. */
        if (errno == EOPNOTSUPP || errno == EPERM)
        {
            be->linkfile = NULL;
            return TRUE;
        }

        /* Otherwise, something else is wrong. */
        xaccBackendSetError ((Backend*)be, ERR_BACKEND_LOCKED);
        unlink (pathbuf);
        close (be->lockfd);
        unlink (be->lockfile);
        return FALSE;
    }

    rc = stat (be->lockfile, &statbuf);
    if (rc)
    {
        /* oops .. stat failed!  This can't happen! */
        xaccBackendSetError ((Backend*)be, ERR_BACKEND_LOCKED);
        unlink (pathbuf);
        close (be->lockfd);
        unlink (be->lockfile);
        return FALSE;
    }

    if (statbuf.st_nlink != 2)
    {
        xaccBackendSetError ((Backend*)be, ERR_BACKEND_LOCKED);
        unlink (pathbuf);
        close (be->lockfd);
        unlink (be->lockfile);
        return FALSE;
    }

    be->linkfile = g_strdup (pathbuf);

    return TRUE;
}

========================================================
Received on 2003-06-23 09:47:45