Files
swift-mirror/stdlib/public/SDK/Foundation/DataThunks.m
Philippe Hausler dc783c064c [Foundation] Remove @_silgen thunks and replace them with shims instead
This avoids indirection by making calls directly to the C implementations which prevents potentials of mismatched intent or changes of calling convention of @_silgen. The added benefit is that all of the shims in this case are no longer visible symbols (anyone using them was not authorized out side of the Foundation overlay). Also the callout methods in the headers now all share similar naming shcemes for easier refactoring and searching in the style of __NS<class><action> style. The previous compiled C/Objective-C source files were built with MRR the new headers MUST be ARC by Swift import rules.

The one caveat is that certain functions MUST avoid the bridge case (since they are part of the bridging code-paths and that would incur a recursive potential) which have the types erased up to NSObject * via the macro NS_NON_BRIDGED.

The remaining @_silgen declarations are either swift functions exposed externally to the rest of Swift’s runtime or are included in NSNumber.gyb which the Foundation team has other plans for removing those @_silgen functions at a later date and Data.swift has one external function left with @_silgen which is blocked by a bug in the compiler which seems to improperly import that particular method as an inline c function.
2017-03-06 09:59:37 -08:00

182 lines
6.7 KiB
Objective-C

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#import <Foundation/Foundation.h>
#import <sys/fcntl.h>
#include "swift/Runtime/Config.h"
#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
static int __NSFileProtectionClassForOptions(NSUInteger options) {
int result;
switch (options & NSDataWritingFileProtectionMask) {
case NSDataWritingFileProtectionComplete: // Class A
result = 1;
break;
case NSDataWritingFileProtectionCompleteUnlessOpen: // Class B
result = 2;
break;
case NSDataWritingFileProtectionCompleteUntilFirstUserAuthentication: // Class C
result = 3;
break;
case NSDataWritingFileProtectionNone: // Class D
result = 4;
break;
default:
result = 0;
break;
}
return result;
}
#endif
static int32_t _NSOpenFileDescriptor(const char *path, NSInteger flags, int protectionClass, NSInteger mode) {
int fd = -1;
if (protectionClass != 0) {
fd = open_dprotected_np(path, flags, protectionClass, 0, mode);
} else {
fd = open(path, flags, mode);
}
return fd;
}
static NSInteger _NSWriteToFileDescriptor(int32_t fd, const void *buffer, NSUInteger length) {
size_t preferredChunkSize = (size_t)length;
size_t numBytesRemaining = (size_t)length;
while (numBytesRemaining > 0UL) {
size_t numBytesRequested = (preferredChunkSize < (1LL << 31)) ? preferredChunkSize : ((1LL << 31) - 1);
if (numBytesRequested > numBytesRemaining) numBytesRequested = numBytesRemaining;
ssize_t numBytesWritten;
do {
numBytesWritten = write(fd, buffer, numBytesRequested);
} while (numBytesWritten < 0L && errno == EINTR);
if (numBytesWritten < 0L) {
return -1;
} else if (numBytesWritten == 0L) {
break;
} else {
numBytesRemaining -= numBytesWritten;
if ((size_t)numBytesWritten < numBytesRequested) break;
buffer = (char *)buffer + numBytesWritten;
}
}
return length - numBytesRemaining;
}
static NSError *_NSErrorWithFilePath(NSInteger code, id pathOrURL) {
NSString *key = [pathOrURL isKindOfClass:[NSURL self]] ? NSURLErrorKey : NSFilePathErrorKey;
return [NSError errorWithDomain:NSCocoaErrorDomain code:code userInfo:[NSDictionary dictionaryWithObjectsAndKeys:pathOrURL, key, nil]];
}
static NSError *_NSErrorWithFilePathAndErrno(NSInteger posixErrno, id pathOrURL, BOOL reading) {
NSInteger code;
if (reading) {
switch (posixErrno) {
case EFBIG: code = NSFileReadTooLargeError; break;
case ENOENT: code = NSFileReadNoSuchFileError; break;
case EPERM: // fallthrough
case EACCES: code = NSFileReadNoPermissionError; break;
case ENAMETOOLONG: code = NSFileReadInvalidFileNameError; break;
default: code = NSFileReadUnknownError; break;
}
} else {
switch (posixErrno) {
case ENOENT: code = NSFileNoSuchFileError; break;
case EPERM: // fallthrough
case EACCES: code = NSFileWriteNoPermissionError; break;
case ENAMETOOLONG: code = NSFileWriteInvalidFileNameError; break;
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
case EDQUOT:
#endif
case ENOSPC: code = NSFileWriteOutOfSpaceError; break;
case EROFS: code = NSFileWriteVolumeReadOnlyError; break;
case EEXIST: code = NSFileWriteFileExistsError; break;
default: code = NSFileWriteUnknownError; break;
}
}
NSString *key = [pathOrURL isKindOfClass:[NSURL self]] ? NSURLErrorKey : NSFilePathErrorKey;
NSDictionary *userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:pathOrURL, key, [NSError errorWithDomain:NSPOSIXErrorDomain code:posixErrno userInfo:nil], NSUnderlyingErrorKey, nil];
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:code userInfo:userInfo];
[userInfo release];
return error;
}
SWIFT_CC(swift)
BOOL __NSDataWriteToURL(NSData *NS_RELEASES_ARGUMENT data, NSURL *NS_RELEASES_ARGUMENT url, NSDataWritingOptions writingOptions, NSError **_Nullable errorPtr) {
assert((writingOptions & NSDataWritingAtomic) == 0);
NSString *path = url.path;
char cpath[1026];
if (![path getFileSystemRepresentation:cpath maxLength:1024]) {
if (errorPtr) *errorPtr = _NSErrorWithFilePath(NSFileWriteInvalidFileNameError, path);
return NO;
}
int protectionClass = 0;
#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
protectionClass = __NSFileProtectionClassForOptions(writingOptions);
#endif
int flags = O_WRONLY|O_CREAT|O_TRUNC;
if (writingOptions & NSDataWritingWithoutOverwriting) {
flags |= O_EXCL;
}
int32_t fd = _NSOpenFileDescriptor(cpath, flags, protectionClass, 0666);
if (fd < 0) {
if (errorPtr) *errorPtr = _NSErrorWithFilePathAndErrno(errno, path, NO);
[url release];
[data release];
return NO;
}
__block BOOL writingFailed = NO;
__block int32_t saveerr = 0;
NSUInteger dataLength = [data length];
[data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
NSUInteger length = byteRange.length;
BOOL success = NO;
if (length > 0) {
NSInteger writtenLength = _NSWriteToFileDescriptor(fd, bytes, length);
success = writtenLength > 0 && (NSUInteger)writtenLength == length;
} else {
success = YES; // Writing nothing always succeeds.
}
if (!success) {
saveerr = errno;
writingFailed = YES;
*stop = YES;
}
}];
if (dataLength && !writingFailed) {
if (fsync(fd) < 0) {
writingFailed = YES;
saveerr = errno;
}
}
if (writingFailed) {
close(fd);
errno = (saveerr);
if (errorPtr) {
*errorPtr = _NSErrorWithFilePathAndErrno(errno, path, NO);
}
[url release];
[data release];
return NO;
}
close(fd);
[url release];
[data release];
return YES;
}