21
21
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
23
23
<title>NSDistributedLock class reference</title>
24
$Date: 2001/12/18 16:54:14 $ $Revision: 1.12 $
24
$Date: 2005/02/22 11:22:44 $ $Revision: 1.20 $
28
28
#include <string.h>
29
#include <Foundation/NSDistributedLock.h>
30
#include <Foundation/NSFileManager.h>
31
#include <Foundation/NSException.h>
32
#include <Foundation/NSValue.h>
33
#include <Foundation/NSDebug.h>
29
#include "Foundation/NSDistributedLock.h"
30
#include "Foundation/NSFileManager.h"
31
#include "Foundation/NSException.h"
32
#include "Foundation/NSValue.h"
33
#include "Foundation/NSDebug.h"
37
static NSFileManager *mgr = nil;
40
* This class does not adopt the [(NSLocking)] protocol but supports locking
41
* across processes, including processes on different machines, as long as
42
* they can access a common filesystem.
37
44
@implementation NSDistributedLock
50
mgr = RETAIN([NSFileManager defaultManager]);
55
* Return a distributed lock for aPath.
56
* See -initWithPath: for details.
39
58
+ (NSDistributedLock*) lockWithPath: (NSString*)aPath
41
60
return AUTORELEASE([[self alloc] initWithPath: aPath]);
64
* Forces release of the lock whether the receiver owns it or not.<br />
65
* Raises an NSGenericException if unable to remove the lock.
46
NSFileManager *fileManager;
48
fileManager = [NSFileManager defaultManager];
49
if ([fileManager removeFileAtPath: _lockPath handler: nil] == NO)
50
[NSException raise: NSGenericException
51
format: @"Failed to remove lock directory '%@' - %s",
52
_lockPath, GSLastErrorStr(errno)];
69
NSDictionary *attributes;
72
attributes = [mgr fileAttributesAtPath: _lockPath traverseLink: YES];
73
if (attributes != nil)
75
NSDate *modDate = [attributes fileModificationDate];
77
if ([mgr removeFileAtPath: _lockPath handler: nil] == NO)
79
const char *err = GSLastErrorStr(errno);
81
attributes = [mgr fileAttributesAtPath: _lockPath traverseLink: YES];
82
if ([modDate isEqual: [attributes fileModificationDate]] == YES)
84
[NSException raise: NSGenericException
85
format: @"Failed to remove lock directory '%@' - %s",
64
- (NSDistributedLock*) initWithPath: (NSString*)aPath
100
* Initialises the reciever with the specified filesystem path.<br />
101
* The location in the filesystem must be accessible for this
102
* to be usable. That is, the processes using the lock must be able
103
* to access, create, and destroy files at the path.<br />
104
* The directory in which the last path component resides must already
105
* exist ... create it using NSFileManager if you need to.
107
- (id) initWithPath: (NSString*)aPath
66
NSFileManager *fileManager;
67
109
NSString *lockDir;
70
112
_lockPath = [aPath copy];
73
fileManager = [NSFileManager defaultManager];
74
115
lockDir = [_lockPath stringByDeletingLastPathComponent];
75
if ([fileManager fileExistsAtPath: lockDir isDirectory: &isDirectory] == NO)
116
if ([mgr fileExistsAtPath: lockDir isDirectory: &isDirectory] == NO)
77
118
NSLog(@"part of the path to the lock file '%@' is missing\n", _lockPath);
88
if ([fileManager isWritableFileAtPath: lockDir] == NO)
129
if ([mgr isWritableFileAtPath: lockDir] == NO)
90
131
NSLog(@"parent directory of lock file '%@' is not writable\n", _lockPath);
94
if ([fileManager isExecutableFileAtPath: lockDir] == NO)
135
if ([mgr isExecutableFileAtPath: lockDir] == NO)
96
137
NSLog(@"parent directory of lock file '%@' is not accessible\n",
146
* Returns the date at which the lock was aquired by <em>any</em>
147
* NSDistributedLock using the same path. If nothing has
148
* the lock, this returns nil.
104
150
- (NSDate*) lockDate
106
NSFileManager *fileManager;
107
152
NSDictionary *attributes;
109
fileManager = [NSFileManager defaultManager];
110
attributes = [fileManager fileAttributesAtPath: _lockPath traverseLink: YES];
111
return [attributes objectForKey: NSFileModificationDate];
154
attributes = [mgr fileAttributesAtPath: _lockPath traverseLink: YES];
155
return [attributes fileModificationDate];
159
* Attempt to aquire the lock and return YES on success, NO on failure.<br />
160
* May raise an NSGenericException if a problem occurs.
116
NSFileManager *fileManager;
117
164
NSMutableDictionary *attributesToSet;
118
165
NSDictionary *attributes;
121
fileManager = [NSFileManager defaultManager];
122
168
attributesToSet = [NSMutableDictionary dictionaryWithCapacity: 1];
123
169
[attributesToSet setObject: [NSNumber numberWithUnsignedInt: 0755]
124
170
forKey: NSFilePosixPermissions];
126
locked = [fileManager createDirectoryAtPath: _lockPath
127
attributes: attributesToSet];
172
locked = [mgr createDirectoryAtPath: _lockPath
173
attributes: attributesToSet];
128
174
if (locked == NO)
135
181
* then either the other process has removed it's lock (and we can retry)
136
182
* or we have a severe problem!
138
if ([fileManager fileExistsAtPath: _lockPath isDirectory: &dir] == NO)
184
if ([mgr fileExistsAtPath: _lockPath isDirectory: &dir] == NO)
140
locked = [fileManager createDirectoryAtPath: _lockPath
141
attributes: attributesToSet];
186
locked = [mgr createDirectoryAtPath: _lockPath
187
attributes: attributesToSet];
142
188
if (locked == NO)
144
190
NSLog(@"Failed to create lock directory '%@' - %s",
150
196
if (locked == NO)
158
attributes = [fileManager fileAttributesAtPath: _lockPath
161
_lockTime = RETAIN([attributes objectForKey: NSFileModificationDate]);
202
attributes = [mgr fileAttributesAtPath: _lockPath
204
if (attributes == nil)
206
[NSException raise: NSGenericException
207
format: @"Unable to get attributes of lock file we made"];
209
ASSIGN(_lockTime, [attributes fileModificationDate]);
215
* Releases the lock. Raises an NSGenericException if unable to release
216
* the lock (for instance if the receiver does not own it or another
217
* process has broken it).
168
NSFileManager *fileManager;
169
221
NSDictionary *attributes;
171
223
if (_lockTime == nil)
172
[NSException raise: NSGenericException format: @"not locked by us"];
225
[NSException raise: NSGenericException format: @"not locked by us"];
175
229
* Don't remove the lock if it has already been broken by someone
176
230
* else and re-created. Unfortunately, there is a window between
177
231
* testing and removing, but we do the bset we can.
179
fileManager = [NSFileManager defaultManager];
180
attributes = [fileManager fileAttributesAtPath: _lockPath traverseLink: YES];
181
if ([_lockTime isEqual: [attributes objectForKey: NSFileModificationDate]])
183
if ([fileManager removeFileAtPath: _lockPath handler: nil] == NO)
184
[NSException raise: NSGenericException
185
format: @"Failed to remove lock directory '%@' - %s",
186
_lockPath, GSLastErrorStr(errno)];
233
attributes = [mgr fileAttributesAtPath: _lockPath traverseLink: YES];
234
if (attributes == nil)
237
[NSException raise: NSGenericException
238
format: @"lock '%@' already broken", _lockPath];
240
if ([_lockTime isEqual: [attributes fileModificationDate]])
243
if ([mgr removeFileAtPath: _lockPath handler: nil] == NO)
245
[NSException raise: NSGenericException
246
format: @"Failed to remove lock directory '%@' - %s",
247
_lockPath, GSLastErrorStr(errno)];
189
NSLog(@"lock '%@' already broken and in use again\n", _lockPath);
253
[NSException raise: NSGenericException
254
format: @"lock '%@' already broken and in use again",