gnustep / libs-base

The GNUstep Base Library is a library of general-purpose, non-graphical Objective C objects.
https://www.gnustep.org/
GNU General Public License v2.0
937 stars 282 forks source link

NSFileManager returns null error e.g. when file exists when copying #305

Open triplef opened 1 year ago

triplef commented 1 year ago

When calling -[NSFileManager copyItemAtPath:toPath:error:] with an existing destination path, the method correctly returns NO but the error is not set. Instead, an NSError with code NSFileWriteFileExistsError should be returned.

Additionally, a log [NSError-initWithDomain:code:userInfo:] with nil domain is output, because -[NSFileManager _errorFrom:to:] will try to use [NSError _last] to get the error domain and code, which is nil in this case.

I think the same might happen in other cases like when the file attributes can’t be read.

hmelder commented 1 year ago

but the error is not set

I just fixed a similar problem in NSRegularExpression. Will look into this one!

hmelder commented 11 months ago

With the operation you described (correct me if I have not reproduced the issue you meant) I get an error message which is different from the one returned by Foundation.

It would be great if you could provide a small code snippet :)

#import <Foundation/Foundation.h>

int main(int argc, const char *argv[]) {
    @autoreleasepool {
        NSString *tempDir;
        NSFileManager *fm;
        NSString *filePath, *content;

        fm = [NSFileManager defaultManager];
        tempDir = NSTemporaryDirectory();
        content = @"Some text";

        [fm createDirectoryAtPath:tempDir withIntermediateDirectories:YES attributes:nil error:nil];

        NSLog(@"Temp dir is %@", tempDir);

        // Create a temporary file
        filePath = [tempDir stringByAppendingPathComponent:@"tempfile.txt"];
        [fm createFileAtPath:filePath contents:[content dataUsingEncoding:NSUTF8StringEncoding] attributes:nil];

        // Produce error
        NSError *error = nil;
        if (![fm copyItemAtPath: filePath toPath: filePath error: &error]) {
             NSLog(@"Domain: %@ Code: %ld UserInfo: %@", [error domain], [error code], [error userInfo]);
        }

        // Remove the temp directory
        [fm removeItemAtPath:tempDir error:nil];
    }
    return 0;
}

Debian (22 = EINVAL (POSIX):

vm@debian:~/GNUstepIssue305$ ./build/objc-boilerplate
2023-12-09 21:50:09.686 objc-boilerplate[76767:76767] Temp dir is /tmp/GNUstepSecure1000
2023-12-09 21:50:09.687 objc-boilerplate[76767:76767] Domain: NSPOSIXErrorDomain Code: 22 UserInfo: {FromPath = "/tmp/GNUstepSecure1000/tempfile.txt"; NSLocalizedDescriptionKey = "Invalid argument"; ToPath = "/tmp/GNUstepSecure1000/tempfile.txt"; }

macOS (NSFileWriteFileExistsError = 516):

2023-12-09 21:52:08.631 objc-boilerplate[7735:342967] Temp dir is /var/folders/x_/m6nkqnp14l75h78kq90d61xw0000gn/T/
2023-12-09 21:52:08.633 objc-boilerplate[7735:342967] Domain: NSCocoaErrorDomain Code: 516 UserInfo: {
    NSDestinationFilePath = "/var/folders/x_/m6nkqnp14l75h78kq90d61xw0000gn/T/tempfile.txt";
    NSFilePath = "/var/folders/x_/m6nkqnp14l75h78kq90d61xw0000gn/T/tempfile.txt";
    NSSourceFilePathErrorKey = "/var/folders/x_/m6nkqnp14l75h78kq90d61xw0000gn/T/tempfile.txt";
    NSUnderlyingError = "Error Domain=NSPOSIXErrorDomain Code=17 \"File exists\"";
    NSUserStringVariant =     (
        Copy
    );
}
hmelder commented 11 months ago

Oh, or is this a Windows-related issue?

triplef commented 11 months ago

Yeah pretty sure I was on Windows when running into this. Thanks for taking a look.