//
//	MiscLockFile.m -- a generic class to simplify keeping an atomic lock file
//		Written by Don Yacktman (c) 1993 by Don Yacktman.
//				Version 1.0.  All rights reserved.
//
//		This notice may not be removed from this source code.
//
//	This object is included in the MiscKit by permission from the author
//	and its use is governed by the MiscKit license, found in the file
//	"LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
//	for a list of all applicable permissions and restrictions.
//	

#import <misckit/misckit.h>
#import <sys/file.h>
#import <sys/vnode.h>

@implementation MiscLockFile

- init
{
	id ret = [super init];
	haveLock = NO;
	return ret;
}

- fileName { return lockFileName; }
- setFileName:aString
{
	if (haveLock) [self unlock];
	lockFileName = aString;
	return self;
}

- lock  // atomically create a lock file.  returns YES on success
{	// lock file contains the PID of the locking process.
	int lockFileFD; char buffer[16];
	if (!lockFileName || ![lockFileName stringValue])
		return self; // always "have" lock if no lock file used
	if (haveLock) return self; // already been done
	lockFileFD = open([lockFileName stringValue],	// file name
			(O_EXCL | O_CREAT | O_RDWR),	// error if exists; create if doesn't
			(VREAD | VWRITE)); // mode is owner r/w
	if (lockFileFD < 0) return nil; // error opening the lock file
	sprintf(buffer, "%d", getpid());
	if (write(lockFileFD, buffer, strlen(buffer)) < 0) return nil; // couldn't write
	if (close(lockFileFD)) return nil; // error closing the lock file
	haveLock = YES;
	return self;
}

- unlock	// remove the lock file.
{
	if (!lockFileName || ![lockFileName stringValue])
		return self; // always "had" lock if no lock file used
	if (!haveLock) return nil;
	if (unlink([lockFileName stringValue])) return nil;  // error in unlink()
	haveLock = NO; // the lock was successfully removed.
	return self;
}

- (BOOL)haveLock { return (haveLock || !lockFileName); }

- copy
{	// copies do not have locks or open logs... only original can!
	id myCopy = [[MiscLockFile alloc] init];
	[myCopy setFileName:lockFileName];
	return myCopy;
}

- read:(NXTypedStream *)stream
{
	[super read:stream];
	lockFileName = NXReadObject(stream);
	haveLock = NO;
	return self;
}

- write:(NXTypedStream *)stream
{
	[super write:stream];
	NXWriteObject(stream, lockFileName);
	return self;
}

// NXTransport protocol implementation:
- encodeUsing:(id <NXEncoding>)portal
{
	[portal encodeObjectBycopy:lockFileName];
	return self;
}

- decodeUsing:(id <NXDecoding>)portal
{
	lockFileName = [portal decodeObject];
	return self;
}

- encodeRemotelyFor:(NXConnection *)connection
	freeAfterEncoding:(BOOL *)flagp isBycopy:(BOOL)isByCopy
{
	if (isByCopy) {
		*flagp = NO; // object will copy.
		return self; //encode object (copy it)
	}
	*flagp = NO; // object will copy.
	// super will encode the proxy otherwise
	return [super encodeRemotelyFor:connection
				freeAfterEncoding:flagp isBycopy:isByCopy];
}

- free
{
	if (haveLock) [self unlock];
	[lockFileName free];
	return [super free];
}

@end
