
/*
 *  LOCKFILE.C
 *
 *  (C) Copyright 1989-1990 by Matthew Dillon,  All Rights Reserved.
 *
 *  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 <exec/types.h>
#include <exec/lists.h>
#include <proto/all.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct List LIST;
typedef struct Node NODE;

typedef struct {
    NODE    Node;
    FILE    *Fi;
    short   Refs;
} LNode;

LIST LockList = { (NODE *)&LockList.lh_Tail, NULL, (NODE *)&LockList.lh_Head };

void FreeLockNode();

void
LockFile(file)
char *file;
{
    char *ptr;

    LNode *node;
    LNode *n;

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


    if (node = malloc(sizeof(LNode) + strlen(ptr) + 16)) {
	node->Node.ln_Name = (char *)(node + 1);
	sprintf(node->Node.ln_Name, "T:%s.LOCK", ptr);

	for (n = (LNode *)LockList.lh_Head; n != (LNode *)&LockList.lh_Tail; n = (LNode *)n->Node.ln_Succ) {
	    if (strcmp(node->Node.ln_Name, n->Node.ln_Name) == 0) {
		++n->Refs;
		free(node);
		return;
	    }
	}

	while ((node->Fi = fopen(node->Node.ln_Name, "w")) == NULL) {
	    sleep(2);
	    chkabort();
	}
	node->Refs = 1;
	AddTail(&LockList, &node->Node);
    }
}

void
UnLockFile(file)
char *file;
{
    LNode *node;
    short len;
    char *ptr;

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

    for (node = (LNode *)LockList.lh_Head; node != (LNode *)&LockList.lh_Tail; node = (LNode *)node->Node.ln_Succ) {
	if (strncmp(ptr, node->Node.ln_Name + 2, len) == 0 && strlen(node->Node.ln_Name) == len + 7) {
	    if (--node->Refs == 0)
		FreeLockNode(node);
	    return;
	}
    }
}

void
UnLockFiles()
{
    LNode *node;

    while ((node = (LNode *)LockList.lh_Head) != (LNode *)&LockList.lh_Tail)
	FreeLockNode(node);
}

void
FreeLockNode(node)
LNode *node;
{
    Remove(node);
    fclose(node->Fi);
    unlink(node->Node.ln_Name);
    free(node);
}

