Search code examples
objective-cnsfilemanager

createFileAtPath & OCUnit & errno blues


I looked here and there but to no avail.

Consider:

- (void) write: (NSString *) xId data:(NSData *) data forClass: (Class) c {
    NSFileManager * fm = [NSFileManager defaultManager] ;

    NSString * instancePath = [self instancePath:xId forClass: c] ;

    errno = 0 ;
    BOOL success = [fm createFileAtPath: instancePath
                               contents: data
                             attributes: nil] ;
    if (!success) {
        ::NSLog(@"Couldn't write to path: %@", instancePath) ;
        ::NSLog(@"Error was code: %d - message: %s", errno, strerror(errno));
    } else {
        ::NSLog(@"COULD write to path: %@", instancePath) ;
        ::NSLog(@"Error was code: %d - message: %s", errno, strerror(errno));
    }
}

Which then prints:

2013-03-22 18:59:27.177 otest[18490:303] COULD write to path: /Users/verec/Library/Application Support/iPhone Simulator/6.1/Documents/cal/ModelRepo/ModelRepo#0.sexp
2013-03-22 18:59:27.177 otest[18490:303] Error was code: 3 - message: No such process
2013-03-22 18:59:27.178 otest[18490:303] Couldn't write to path: /Users/verec/Library/Application Support/iPhone Simulator/6.1/Documents/cal/ModelContainer/20130322.sexp
2013-03-22 18:59:27.178 otest[18490:303] Error was code: 3 - message: No such process
  1. Why is it that errno is not 0 even though `success' is YES in the first case (the "COULD" case)
  2. Can anyone spot the difference in the actual path that makes success=YES in the first ("COULD") case but success=NO in the second ("Couldn't")?

This is while running a OCUnit test, Xcode 4.6.1 Simulator running iOS 6.1

I'm just puzzled :-(


Solution

    • The errno variable is generally only set by system calls (and some library functions) if the call failed. It is not modified if a system call succeeded, and may contain a non-zero value from a previous error.

    • One should print or save errno immediately after a failed system call. In your case,

      NSLog(@"Couldn't write to path: %@", instancePath);
      

      actually modifies errno. ("No such process" is very unlikely to be the correct failure reason.)

    • For the same reason, you cannot assume that errno contains the correct value after createFileAtPath failed. It actually did in my test, but it is not documented that this method sets/preserves errno correctly.