/* Implementation for GNU Objective-C version of NSDistributedLock Copyright (C) 1997 Free Software Foundation, Inc. Written by: Richard Frith-Macdonald 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 #include #include #include #include #include #include #include @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