
/*
 *  Lock and unlock a file.  Under AmigaDOS, openning a file mode 1006
 *  (accomplished with fopen(,"w"), locks the file exclusively.  That
 *  is, further fopen()s will fail.  Thus, we need only keep a live
 *  file descriptor to 'lock' the file.
 *
 *  This is advantagious because if the program exits without removing
 *  the lock file we are still ok... the file is unlocked by virtue of
 *  the file descriptor getting closed.
 */

#include "prefs.h"
#ifdef LATTICE
#include <proto/exec.h>
#include <proto/dos.h>
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>



#define LOCKDIR		"T:"


struct LockNode {
	struct LockNode *next;
	FILE *fp;
	char *file;
	long refs;
};



Prototype void LockFile(char *);
Prototype void UnLockFile(char *);
Prototype void UnLockFiles(void);
Prototype BOOL FileIsLocked(char *);
Local void FreeLockNode(struct LockNode *);



struct LockNode *LockList = NULL;



void LockFile(char *file)
{
  char *ptr;
  struct LockNode *node;
  struct LockNode *n;

  for (ptr = file+strlen(file); ptr >= file && *ptr!='/' && *ptr!=':'; --ptr);
  ++ptr;

  if (node=malloc(sizeof(struct LockNode))) {
    node->next = LockList;
    node->refs = 1L;
    if (node->file=malloc(strlen(LOCKDIR)+strlen(ptr)+6)) {
      sprintf(node->file,"%s%s.LOCK",LOCKDIR,ptr);
      for (n=LockList;n;n=n->next) {
        if (!stricmp(node->file,n->file)) {
          n->refs = n->refs + 1L;
          free(node->file);
          free(node);
          return;
        }
      }
      while (!(node->fp=fopen(node->file, "w")))
        Delay(100L);

      LockList = node;
    }
  }
}



/*
 *  Check to see whether a file is locked.  We could try to fopen the
 *  file for 'w', but this causes unnecesary filesystem activity
 */

BOOL FileIsLocked(char *file)
{
  char *ptr;
  char *buf;
  BPTR lock;

  for (ptr = file+strlen(file); ptr >= file && *ptr!='/' && *ptr!=':'; --ptr);
  ++ptr;

  if (buf=malloc(strlen(LOCKDIR)+strlen(ptr)+6)) {
    sprintf(buf,"%s%s.LOCK",LOCKDIR,ptr);

    if (lock=Lock(buf,EXCLUSIVE_LOCK)) {
      UnLock(lock);
      free(buf);
      return(FALSE);
    }

    free(buf);

    if (IoErr()==ERROR_OBJECT_IN_USE)
      return(TRUE);
  }
  return(FALSE);
}



void UnLockFile(char *file)
{
  struct LockNode *node,*last;
  char *buf;
  char *ptr;

  for (ptr = file+strlen(file); ptr >= file && *ptr!='/' && *ptr!=':'; --ptr);
  ++ptr;

  if (buf=malloc(strlen(LOCKDIR)+strlen(ptr)+6)) {
    sprintf(buf,"%s%s.LOCK",LOCKDIR,ptr);

    for (node=LockList,last=NULL;node;node=node->next) {
      if (!stricmp(buf,node->file)) {
        node->refs = node->refs - 1L;
        if (!node->refs) {
          if (last)
            last->next = node->next;
          else
            LockList = node->next;
          FreeLockNode(node);
          free(buf);
          return;
        }
      }
      last = node;
    }

    free(buf);
  }
}



void UnLockFiles(void)
{
  struct LockNode *node,*next;

  node = LockList;

  while (node) {
    next = node->next;
    FreeLockNode(node);
    node = next;
  }
}



static void FreeLockNode(struct LockNode *node)
{
  fclose(node->fp);
  unlink(node->file);
  free(node->file);
  free(node);
}

