Wed 29 Feb 2012 08:07:47 PM UTC, original submission:
Calling -[NSFileManager createDirectoryAtPath: withIntermediateDirectories: attributes: error:] with an already-existing directory whose path is (at least?) two levels deep, returns the wrong error code. The output NSError has code 2 (ENOENT), when it should be EEXIST. (It may be possible for other incorrect error codes to be returned too.)
STEPS TO REPRODUCE
$ mkdir /tmp/foobar
NSError* error = nil;
[[NSFIleManager defaultManager] createDirectoryAtPath: @"/tmp/foobar" withIntermediateDirectories: NO attributes: nil error: &error];
NSAssert(error.code == EEXIST, @"Wrong error %@", error);
DIAGNOSIS
The above method calls the older method -createDirectoryAtPath:attributes:, and if that fails it calls -[NSError _lastError] to generate the NSError to be returned. This assumes the relevant error code is contained in errno.
However, in the case where the directory already exists, the older method returns NO after a successful stat() call, so errno never actually gets set to EEXIST. Instead the value from the previous error (whatever that was) is left behind.
The best fix appears to be to manually set errno=EEXIST in this situation. (See patch below.)
There may be other code paths in that method that have similar issues; I haven't checked.
CONFIGURATION
URL: http://svn.gna.org/svn/gnustep/libs/base/trunk/Source
Repository Root: http://svn.gna.org/svn/gnustep
Repository UUID: 72102866-910b-0410-8b05-ffd578937521
Revision: 34837
My OS is Ubuntu 11 (current according to software update).
I'm compiling with Clang 3.1 (trunk 151546).
PATCH
Index: NSFileManager.m
===================================================================
--- NSFileManager.m (revision 34837)
+++ NSFileManager.m (working copy)
@@ -854,6 +854,7 @@
{
ASSIGN(_lastError,
@"Could not create directory - already exists");
+ errno = EEXIST;
return NO;
}
}
|