mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-25 09:41:15 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@4902 72102866-910b-0410-8b05-ffd578937521
192 lines
5.4 KiB
Objective-C
192 lines
5.4 KiB
Objective-C
/* Implementation for GNU Objective-C version of NSDistributedLock
|
|
Copyright (C) 1997 Free Software Foundation, Inc.
|
|
|
|
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
Created: November 1997
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; if not, write to the Free
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <string.h>
|
|
#include <Foundation/NSDistributedLock.h>
|
|
#include <Foundation/NSFileManager.h>
|
|
#include <Foundation/NSException.h>
|
|
#include <Foundation/NSValue.h>
|
|
#include <Foundation/NSDebug.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
@implementation NSDistributedLock
|
|
|
|
+ (NSDistributedLock*) lockWithPath: (NSString*)aPath
|
|
{
|
|
return AUTORELEASE([[self alloc] initWithPath: aPath]);
|
|
}
|
|
|
|
- (void) breakLock
|
|
{
|
|
NSFileManager *fileManager;
|
|
|
|
fileManager = [NSFileManager defaultManager];
|
|
if ([fileManager removeFileAtPath: _lockPath handler: nil] == NO)
|
|
[NSException raise: NSGenericException
|
|
format: @"Failed to remove lock directory '%@' - %s",
|
|
_lockPath, strerror(errno)];
|
|
RELEASE(_lockTime);
|
|
_lockTime = nil;
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
RELEASE(_lockPath);
|
|
RELEASE(_lockTime);
|
|
[super dealloc];
|
|
}
|
|
|
|
- (NSDistributedLock*) initWithPath: (NSString*)aPath
|
|
{
|
|
NSFileManager *fileManager;
|
|
NSString *lockDir;
|
|
BOOL isDirectory;
|
|
|
|
_lockPath = [aPath copy];
|
|
_lockTime = nil;
|
|
|
|
fileManager = [NSFileManager defaultManager];
|
|
lockDir = [_lockPath stringByDeletingLastPathComponent];
|
|
if ([fileManager fileExistsAtPath: lockDir isDirectory: &isDirectory] == NO)
|
|
{
|
|
NSLog(@"part of the path to the lock file '%@' is missing\n", _lockPath);
|
|
RELEASE(self);
|
|
return nil;
|
|
}
|
|
if (isDirectory == NO)
|
|
{
|
|
NSLog(@"part of the path to the lock file '%@' is not a directory\n",
|
|
_lockPath);
|
|
RELEASE(self);
|
|
return nil;
|
|
}
|
|
if ([fileManager isWritableFileAtPath: lockDir] == NO)
|
|
{
|
|
NSLog(@"parent directory of lock file '%@' is not writable\n", _lockPath);
|
|
RELEASE(self);
|
|
return nil;
|
|
}
|
|
if ([fileManager isExecutableFileAtPath: lockDir] == NO)
|
|
{
|
|
NSLog(@"parent directory of lock file '%@' is not accessible\n",
|
|
_lockPath);
|
|
RELEASE(self);
|
|
return nil;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (NSDate*) lockDate
|
|
{
|
|
NSFileManager *fileManager;
|
|
NSDictionary *attributes;
|
|
|
|
fileManager = [NSFileManager defaultManager];
|
|
attributes = [fileManager fileAttributesAtPath: _lockPath traverseLink: YES];
|
|
return [attributes objectForKey: NSFileModificationDate];
|
|
}
|
|
|
|
- (BOOL) tryLock
|
|
{
|
|
NSFileManager *fileManager;
|
|
NSMutableDictionary *attributesToSet;
|
|
NSDictionary *attributes;
|
|
BOOL locked;
|
|
|
|
fileManager = [NSFileManager defaultManager];
|
|
attributesToSet = [NSMutableDictionary dictionaryWithCapacity: 1];
|
|
[attributesToSet setObject: [NSNumber numberWithUnsignedInt: 0755]
|
|
forKey: NSFilePosixPermissions];
|
|
|
|
locked = [fileManager createDirectoryAtPath: _lockPath
|
|
attributes: attributesToSet];
|
|
if (locked == NO)
|
|
{
|
|
BOOL dir;
|
|
|
|
/*
|
|
* We expect the directory creation to have failed because it already
|
|
* exists as another processes lock. If the directory doesn't exist,
|
|
* then either the other process has removed it's lock (and we can retry)
|
|
* or we have a severe problem!
|
|
*/
|
|
if ([fileManager fileExistsAtPath: _lockPath isDirectory: &dir] == NO)
|
|
{
|
|
locked = [fileManager createDirectoryAtPath: _lockPath
|
|
attributes: attributesToSet];
|
|
if (locked == NO)
|
|
{
|
|
NSLog(@"Failed to create lock directory '%@' - %s",
|
|
_lockPath, strerror(errno));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (locked == NO)
|
|
{
|
|
RELEASE(_lockTime);
|
|
_lockTime = nil;
|
|
return NO;
|
|
}
|
|
else
|
|
{
|
|
attributes = [fileManager fileAttributesAtPath: _lockPath
|
|
traverseLink: YES];
|
|
RELEASE(_lockTime);
|
|
_lockTime = RETAIN([attributes objectForKey: NSFileModificationDate]);
|
|
return YES;
|
|
}
|
|
}
|
|
|
|
- (void) unlock
|
|
{
|
|
NSFileManager *fileManager;
|
|
NSDictionary *attributes;
|
|
|
|
if (_lockTime == nil)
|
|
[NSException raise: NSGenericException format: @"not locked by us"];
|
|
|
|
/*
|
|
* Don't remove the lock if it has already been broken by someone
|
|
* else and re-created. Unfortunately, there is a window between
|
|
* testing and removing, but we do the bset we can.
|
|
*/
|
|
fileManager = [NSFileManager defaultManager];
|
|
attributes = [fileManager fileAttributesAtPath: _lockPath traverseLink: YES];
|
|
if ([_lockTime isEqual: [attributes objectForKey: NSFileModificationDate]])
|
|
{
|
|
if ([fileManager removeFileAtPath: _lockPath handler: nil] == NO)
|
|
[NSException raise: NSGenericException
|
|
format: @"Failed to remove lock directory '%@' - %s",
|
|
_lockPath, strerror(errno)];
|
|
}
|
|
else
|
|
NSLog(@"lock '%@' already broken and in use again\n", _lockPath);
|
|
|
|
RELEASE(_lockTime);
|
|
_lockTime = nil;
|
|
}
|
|
|
|
@end
|