static CFTypeRef fileCopyProperty(struct _CFStream *stream, CFStringRef propertyName, void *info) { CFTypeRef result = NULL; _CFFileStreamContext *fileStream = (_CFFileStreamContext *)info; if (CFEqual(propertyName, kCFStreamPropertyFileCurrentOffset)) { // NOTE that this does a lseek of 0 from the current location in // order to populate the offset field which will then be used to // create the resulting value. if (!__CFBitIsSet(fileStream->flags, APPEND) && fileStream->fd != -1) { fileStream->offset = lseek(fileStream->fd, 0, SEEK_CUR); } if (fileStream->offset != -1) { result = CFNumberCreate(CFGetAllocator((CFTypeRef)stream), kCFNumberSInt64Type, &(fileStream->offset)); } #if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX } else if (CFEqual(propertyName, _kCFStreamPropertyFileNativeHandle)) { int fd = fileStream->fd; if (fd != -1) { result = CFDataCreate(CFGetAllocator((CFTypeRef) stream), (const uint8_t *)&fd, sizeof(fd)); } #endif } return result; }
static Boolean fileSetProperty(struct _CFStream *stream, CFStringRef prop, CFTypeRef val, void *info) { Boolean result = FALSE; _CFFileStreamContext *fileStream = (_CFFileStreamContext *)info; if (CFEqual(prop, kCFStreamPropertyAppendToFile) && CFGetTypeID(stream) == CFWriteStreamGetTypeID() && CFWriteStreamGetStatus((CFWriteStreamRef)stream) == kCFStreamStatusNotOpen) { if (val == kCFBooleanTrue) { __CFBitSet(fileStream->flags, APPEND); fileStream->offset = -1; // Can't offset and append on the stream } else { __CFBitClear(fileStream->flags, APPEND); } result = TRUE; } else if (CFEqual(prop, kCFStreamPropertyFileCurrentOffset)) { if (!__CFBitIsSet(fileStream->flags, APPEND)) { result = CFNumberGetValue((CFNumberRef)val, kCFNumberSInt64Type, &(fileStream->offset)); } if ((fileStream->fd != -1) && (lseek(fileStream->fd, fileStream->offset, SEEK_SET) == -1)) { result = FALSE; } } return result; }
static CFIndex fileRead(CFReadStreamRef stream, UInt8 *buffer, CFIndex bufferLength, CFStreamError *errorCode, Boolean *atEOF, void *info) { _CFFileStreamContext *ctxt = (_CFFileStreamContext *)info; CFIndex result; result = fdRead(ctxt->fd, buffer, bufferLength, errorCode, atEOF); #ifdef REAL_FILE_SCHEDULING if (__CFBitIsSet(ctxt->flags, SCHEDULE_AFTER_READ)) { __CFBitClear(ctxt->flags, SCHEDULE_AFTER_READ); if (!*atEOF && ctxt->rlInfo.cffd) { struct stat statbuf; int ret = fstat(ctxt->fd, &statbuf); if (0 <= ret && (S_IFREG == (statbuf.st_mode & S_IFMT))) { off_t offset = lseek(ctxt->fd, 0, SEEK_CUR); if (statbuf.st_size == offset) { _CFFileDescriptorInduceFakeReadCallBack(ctxt->rlInfo.cffd); } } } if (ctxt->rlInfo.cffd) { CFFileDescriptorEnableCallBacks(ctxt->rlInfo.cffd, kCFFileDescriptorReadCallBack); } } #else if (*atEOF) __CFBitSet(ctxt->flags, AT_EOF); if (ctxt->scheduled > 0 && !*atEOF) { CFReadStreamSignalEvent(stream, kCFStreamEventHasBytesAvailable, NULL); } #endif return result; }
__private_extern__ CFErrorRef _CFErrorFromStreamError(CFAllocatorRef alloc, CFStreamError *streamError) { CFErrorRef result; Boolean canUpCall; __CFSpinLock(&(CFNetworkSupport.lock)); if (!__CFBitIsSet(CFNetworkSupport.flags, kTriedToLoad)) initializeCFNetworkSupport(); canUpCall = (CFNetworkSupport._CFErrorCreateWithStreamError != NULL); __CFSpinUnlock(&(CFNetworkSupport.lock)); if (canUpCall) { result = CFNETWORK_CALL(_CFErrorCreateWithStreamError, (alloc, streamError)); } else { if (streamError->domain == kCFStreamErrorDomainPOSIX) { return CFErrorCreate(alloc, kCFErrorDomainPOSIX, streamError->error, NULL); } else if (streamError->domain == kCFStreamErrorDomainMacOSStatus) { return CFErrorCreate(alloc, kCFErrorDomainOSStatus, streamError->error, NULL); } else { CFStringRef key = CFSTR("CFStreamErrorDomainKey"); CFNumberRef value = CFNumberCreate(alloc, kCFNumberCFIndexType, &streamError->domain); CFDictionaryRef dict = CFDictionaryCreate(alloc, (const void **)(&key), (const void **)(&value), 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); result = CFErrorCreate(alloc, CFSTR("BogusCFStreamErrorCompatibilityDomain"), streamError->error, dict); CFRelease(value); CFRelease(dict); } } return result; }
__private_extern__ CFStreamError _CFStreamErrorFromError(CFErrorRef error) { CFStreamError result; Boolean canUpCall; __CFSpinLock(&(CFNetworkSupport.lock)); if (!__CFBitIsSet(CFNetworkSupport.flags, kTriedToLoad)) initializeCFNetworkSupport(); canUpCall = (CFNetworkSupport._CFStreamErrorFromCFError != NULL); __CFSpinUnlock(&(CFNetworkSupport.lock)); if (canUpCall) { result = CFNETWORK_CALL(_CFStreamErrorFromCFError, (error)); } else { CFStringRef domain = CFErrorGetDomain(error); if (CFEqual(domain, kCFErrorDomainPOSIX)) { result.domain = kCFStreamErrorDomainPOSIX; } else if (CFEqual(domain, kCFErrorDomainOSStatus)) { result.domain = kCFStreamErrorDomainMacOSStatus; } else if (CFEqual(domain, kCFErrorDomainMach)) { result.domain = 11; // kCFStreamErrorDomainMach, but that symbol is in CFNetwork } else { result.domain = kCFStreamErrorDomainCustom; } result.error = CFErrorGetCode(error); } return result; }
static Boolean fileCanRead(CFReadStreamRef stream, void *info) { _CFFileStreamContext *ctxt = (_CFFileStreamContext *)info; #ifdef REAL_FILE_SCHEDULING return fdCanRead(ctxt->fd); #else return !__CFBitIsSet(ctxt->flags, AT_EOF); #endif }
static void createPair(CFAllocatorRef alloc, CFStringRef host, UInt32 port, CFSocketNativeHandle sock, const CFSocketSignature* sig, CFReadStreamRef *readStream, CFWriteStreamRef *writeStream) { if (readStream) *readStream = NULL; if (writeStream) *writeStream = NULL; __CFSpinLock(&(CFNetworkSupport.lock)); if (!__CFBitIsSet(CFNetworkSupport.flags, kTriedToLoad)) initializeCFNetworkSupport(); __CFSpinUnlock(&(CFNetworkSupport.lock)); CFNETWORK_CALL(_CFSocketStreamCreatePair, (alloc, host, port, sock, sig, readStream, writeStream)); }
static Boolean constructFD(_CFFileStreamContext *fileStream, CFStreamError *error, Boolean forRead, struct _CFStream *stream) { int flags = forRead ? O_RDONLY : (O_CREAT | O_TRUNC | O_WRONLY); #if DEPLOYMENT_TARGET_WINDOWS wchar_t path[CFMaxPathSize]; flags |= (_O_BINARY|_O_NOINHERIT); if (_CFURLGetWideFileSystemRepresentation(fileStream->url, TRUE, path, CFMaxPathSize) == FALSE) #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI char path[CFMaxPathSize]; if (CFURLGetFileSystemRepresentation(fileStream->url, TRUE, (UInt8 *)path, CFMaxPathSize) == FALSE) #endif { error->error = ENOENT; error->domain = kCFStreamErrorDomainPOSIX; return FALSE; } if (__CFBitIsSet(fileStream->flags, APPEND)) { flags |= O_APPEND; flags &= ~O_TRUNC; } do { #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI fileStream->fd = open((const char *)path, flags, 0666); #elif DEPLOYMENT_TARGET_WINDOWS fileStream->fd = _wopen(path, flags, 0666); #endif if (fileStream->fd < 0) break; if ((fileStream->offset != -1) && (lseek(fileStream->fd, fileStream->offset, SEEK_SET) == -1)) break; #ifdef REAL_FILE_SCHEDULING if (fileStream->rlInfo.rlArray != NULL) { constructCFFD(fileStream, forRead, stream); } #endif return TRUE; } while (1); __CFBitSet(fileStream->flags, USE_RUNLOOP_ARRAY); error->error = errno; error->domain = kCFStreamErrorDomainPOSIX; return FALSE; }
static CFIndex fileWrite(CFWriteStreamRef stream, const UInt8 *buffer, CFIndex bufferLength, CFStreamError *errorCode, void *info) { _CFFileStreamContext *fileStream = ((_CFFileStreamContext *)info); CFIndex result = fdWrite(fileStream->fd, buffer, bufferLength, errorCode); #ifdef REAL_FILE_SCHEDULING if (__CFBitIsSet(fileStream->flags, SCHEDULE_AFTER_WRITE)) { __CFBitClear(fileStream->flags, SCHEDULE_AFTER_WRITE); if (fileStream->rlInfo.cffd) { CFFileDescriptorEnableCallBacks(fileStream->rlInfo.cffd, kCFFileDescriptorWriteCallBack); } } #else if (fileStream->scheduled > 0) { CFWriteStreamSignalEvent(stream, kCFStreamEventCanAcceptBytes, NULL); } #endif return result; }
static Boolean constructFD(_CFFileStreamContext *fileStream, CFStreamError *error, Boolean forRead, struct _CFStream *stream) { int flags = forRead ? O_RDONLY : (O_CREAT | O_TRUNC | O_WRONLY); // WINOBJC: improve code reuse here by letting the underlying open implementation handle the narrow/wide conversions etc. char path[CFMaxPathSize]; #if DEPLOYMENT_TARGET_WINDOWS flags |= (_O_BINARY|_O_NOINHERIT); #endif if (CFURLGetFileSystemRepresentation(fileStream->url, TRUE, (UInt8 *)path, CFMaxPathSize) == FALSE) { error->error = ENOENT; error->domain = kCFStreamErrorDomainPOSIX; return FALSE; } if (__CFBitIsSet(fileStream->flags, APPEND)) { flags |= O_APPEND; flags &= ~O_TRUNC; } do { fileStream->fd = open((const char *)path, flags, 0666); if (fileStream->fd < 0) break; if ((fileStream->offset != -1) && (lseek(fileStream->fd, fileStream->offset, SEEK_SET) == -1)) break; #ifdef REAL_FILE_SCHEDULING if (fileStream->rlInfo.rlArray != NULL) { constructCFFD(fileStream, forRead, stream); } #endif return TRUE; } while (1); __CFBitSet(fileStream->flags, USE_RUNLOOP_ARRAY); error->error = errno; error->domain = kCFStreamErrorDomainPOSIX; return FALSE; }
static void fileUnschedule(struct _CFStream *stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info) { _CFFileStreamContext *fileStream = (_CFFileStreamContext *)info; #ifdef REAL_FILE_SCHEDULING Boolean isReadStream = (CFGetTypeID(stream) == CFReadStreamGetTypeID()); CFStreamStatus status = isReadStream ? CFReadStreamGetStatus((CFReadStreamRef)stream) : CFWriteStreamGetStatus((CFWriteStreamRef)stream); if (status == kCFStreamStatusNotOpen) { // Not opened yet if (fileStream->rlInfo.rlArray) { CFMutableArrayRef runloops = fileStream->rlInfo.rlArray; CFIndex i, c; for (i = 0, c = CFArrayGetCount(runloops); i+1 < c; i += 2) { if (CFEqual(CFArrayGetValueAtIndex(runloops, i), runLoop) && CFEqual(CFArrayGetValueAtIndex(runloops, i+1), runLoopMode)) { CFArrayRemoveValueAtIndex(runloops, i); CFArrayRemoveValueAtIndex(runloops, i); break; } } } } else if (fileStream->rlInfo.cffd) { if (__CFBitIsSet(fileStream->flags, USE_RUNLOOP_ARRAY)) { // we know that fileStream->rlInfo.rlArray is non-NULL because it is in a union with fileStream->rlInfo.cffd CFMutableArrayRef runloops = fileStream->rlInfo.rlArray; CFIndex i, c; for (i = 0, c = CFArrayGetCount(runloops); i+1 < c; i += 2) { if (CFEqual(CFArrayGetValueAtIndex(runloops, i), runLoop) && CFEqual(CFArrayGetValueAtIndex(runloops, i+1), runLoopMode)) { CFArrayRemoveValueAtIndex(runloops, i); CFArrayRemoveValueAtIndex(runloops, i); break; } } } else { CFRunLoopSourceRef rlSrc = CFFileDescriptorCreateRunLoopSource(CFGetAllocator(stream), fileStream->rlInfo.cffd, 0); CFRunLoopRemoveSource(runLoop, rlSrc, runLoopMode); CFRelease(rlSrc); } } #else if (fileStream->scheduled > 0) fileStream->scheduled--; #endif }