Artifact 77e3c3a21e73002b35c641b3c6848b7eb15b05b2adc4311abad41049f1b540df:
- File
src/OFFile.m
— part of check-in
[fe2cbe0021]
at
2018-04-22 16:13:04
on branch trunk
— runtime: Define BOOL to be the same as bool
As we define the ABI, we can just replace BOOL with bool everywhere,
including in ObjFW itself. For the Apple platforms where BOOL and bool
are different, this is not a problem as BOOL and bool are passed and
returned the same way in the ABI.This still defines BOOL to bool for compatibility, except on AmigaOS and
Wii, which both have its own BOOL type. (user: js, size: 10973) [annotate] [blame] [check-ins using]
/* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, * 2018 * Jonathan Schleifer <js@heap.zone> * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #include <assert.h> #include <errno.h> #ifdef HAVE_FCNTL_H # include <fcntl.h> #endif #include "unistd_wrapper.h" #ifdef HAVE_SYS_STAT_H # include <sys/stat.h> #endif #import "OFFile.h" #import "OFLocalization.h" #import "OFString.h" #import "OFURL.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFNotOpenException.h" #import "OFOpenItemFailedException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFSeekFailedException.h" #import "OFWriteFailedException.h" #ifdef OF_WINDOWS # include <windows.h> #endif #ifdef OF_WII # include <fat.h> #endif #ifdef OF_NINTENDO_DS # include <stdbool.h> # include <filesystem.h> #endif #ifndef O_BINARY # define O_BINARY 0 #endif #ifndef O_CLOEXEC # define O_CLOEXEC 0 #endif #ifndef O_EXCL # define O_EXCL 0 #endif #ifndef O_EXLOCK # define O_EXLOCK 0 #endif #ifndef OF_MORPHOS # define closeHandle(h) close(h) #else struct of_file_handle { of_file_handle_t previous, next; BPTR handle; bool append; } *firstHandle = NULL; static void closeHandle(of_file_handle_t handle) { Close(handle->handle); if (handle->previous != NULL) handle->previous->next = handle->next; if (handle->next != NULL) handle->next->previous = handle->previous; if (firstHandle == handle) firstHandle = handle->next; free(handle); } OF_DESTRUCTOR() { for (of_file_handle_t iter = firstHandle; iter != NULL; iter = iter->next) Close(iter->handle); } #endif #ifndef OF_MORPHOS static int parseMode(const char *mode) { if (strcmp(mode, "r") == 0) return O_RDONLY; if (strcmp(mode, "r+") == 0) return O_RDWR; if (strcmp(mode, "w") == 0) return O_WRONLY | O_CREAT | O_TRUNC; if (strcmp(mode, "wx") == 0) return O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK; if (strcmp(mode, "w+") == 0) return O_RDWR | O_CREAT | O_TRUNC; if (strcmp(mode, "w+x") == 0) return O_RDWR | O_CREAT | O_EXCL | O_EXLOCK; if (strcmp(mode, "a") == 0) return O_WRONLY | O_CREAT | O_APPEND; if (strcmp(mode, "a+") == 0) return O_RDWR | O_CREAT | O_APPEND; return -1; } #else static int parseMode(const char *mode, bool *append) { *append = false; if (strcmp(mode, "r") == 0) return MODE_OLDFILE; if (strcmp(mode, "r+") == 0) return MODE_OLDFILE; if (strcmp(mode, "w") == 0) return MODE_NEWFILE; if (strcmp(mode, "wx") == 0) return MODE_NEWFILE; if (strcmp(mode, "w+") == 0) return MODE_NEWFILE; if (strcmp(mode, "w+x") == 0) return MODE_NEWFILE; if (strcmp(mode, "a") == 0) { *append = true; return MODE_READWRITE; } if (strcmp(mode, "a+") == 0) { *append = true; return MODE_READWRITE; } return -1; } #endif @implementation OFFile + (void)initialize { if (self != [OFFile class]) return; #ifdef OF_WII if (!fatInitDefault()) @throw [OFInitializationFailedException exceptionWithClass: self]; #endif #ifdef OF_NINTENDO_DS if (!nitroFSInit(NULL)) @throw [OFInitializationFailedException exceptionWithClass: self]; #endif } + (instancetype)fileWithPath: (OFString *)path mode: (OFString *)mode { return [[[self alloc] initWithPath: path mode: mode] autorelease]; } + (instancetype)fileWithURL: (OFURL *)URL mode: (OFString *)mode { return [[[self alloc] initWithURL: URL mode: mode] autorelease]; } + (instancetype)fileWithHandle: (of_file_handle_t)handle { return [[[self alloc] initWithHandle: handle] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } - (instancetype)initWithPath: (OFString *)path mode: (OFString *)mode { of_file_handle_t handle; @try { void *pool = objc_autoreleasePoolPush(); int flags; #ifndef OF_MORPHOS if ((flags = parseMode([mode UTF8String])) == -1) @throw [OFInvalidArgumentException exception]; flags |= O_BINARY | O_CLOEXEC; # if defined(OF_WINDOWS) if ((handle = _wopen([path UTF16String], flags, _S_IREAD | _S_IWRITE)) == -1) # elif defined(OF_HAVE_OFF64_T) if ((handle = open64([path cStringWithEncoding: [OFLocalization encoding]], flags, 0666)) == -1) # else if ((handle = open([path cStringWithEncoding: [OFLocalization encoding]], flags, 0666)) == -1) # endif @throw [OFOpenItemFailedException exceptionWithPath: path mode: mode errNo: errno]; #else if ((handle = malloc(sizeof(*handle))) == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: sizeof(*handle)]; @try { if ((flags = parseMode([mode UTF8String], &handle->append)) == -1) @throw [OFInvalidArgumentException exception]; if ((handle->handle = Open([path cStringWithEncoding: [OFLocalization encoding]], flags)) == 0) { int errNo; switch (IoErr()) { case ERROR_OBJECT_IN_USE: case ERROR_DISK_NOT_VALIDATED: errNo = EBUSY; break; case ERROR_OBJECT_NOT_FOUND: errNo = ENOENT; break; case ERROR_DISK_WRITE_PROTECTED: errNo = EROFS; break; case ERROR_WRITE_PROTECTED: case ERROR_READ_PROTECTED: errNo = EACCES; break; default: errNo = 0; break; } @throw [OFOpenItemFailedException exceptionWithPath: path mode: mode errNo: errNo]; } if (handle->append) { if (Seek64(handle->handle, 0, OFFSET_END) == -1) { Close(handle->handle); @throw [OFOpenItemFailedException exceptionWithPath: path mode: mode errNo: EIO]; } } handle->previous = NULL; handle->next = firstHandle; if (firstHandle != NULL) firstHandle->previous = handle; firstHandle = handle; } @catch (id e) { free(handle); @throw e; } #endif objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; } @try { self = [self initWithHandle: handle]; } @catch (id e) { closeHandle(handle); @throw e; } return self; } - (instancetype)initWithURL: (OFURL *)URL mode: (OFString *)mode { void *pool = objc_autoreleasePoolPush(); OFString *fileSystemRepresentation; @try { fileSystemRepresentation = [URL fileSystemRepresentation]; } @catch (id e) { [self release]; @throw e; } self = [self initWithPath: fileSystemRepresentation mode: mode]; objc_autoreleasePoolPop(pool); return self; } - (instancetype)initWithHandle: (of_file_handle_t)handle { self = [super init]; _handle = handle; return self; } - (bool)lowlevelIsAtEndOfStream { if (_handle == OF_INVALID_FILE_HANDLE) @throw [OFNotOpenException exceptionWithObject: self]; return _atEndOfStream; } - (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { ssize_t ret; if (_handle == OF_INVALID_FILE_HANDLE) @throw [OFNotOpenException exceptionWithObject: self]; #if defined(OF_WINDOWS) if (length > UINT_MAX) @throw [OFOutOfRangeException exception]; if ((ret = read(_handle, buffer, (unsigned int)length)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length errNo: errno]; #elif defined(OF_MORPHOS) if (length > LONG_MAX) @throw [OFOutOfRangeException exception]; if ((ret = Read(_handle->handle, buffer, length)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length errNo: EIO]; #else if ((ret = read(_handle, buffer, length)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length errNo: errno]; #endif if (ret == 0) _atEndOfStream = true; return ret; } - (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { if (_handle == OF_INVALID_FILE_HANDLE) @throw [OFNotOpenException exceptionWithObject: self]; #if defined(OF_WINDOWS) int bytesWritten; if (length > INT_MAX) @throw [OFOutOfRangeException exception]; if ((bytesWritten = write(_handle, buffer, (int)length)) < 0) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: 0 errNo: errno]; #elif defined(OF_MORPHOS) LONG bytesWritten; if (length > LONG_MAX) @throw [OFOutOfRangeException exception]; if (_handle->append) { if (Seek64(_handle->handle, 0, OFFSET_END) == -1) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: 0 errNo: EIO]; } if ((bytesWritten = Write(_handle->handle, (void *)buffer, length)) < 0) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: 0 errNo: EIO]; #else ssize_t bytesWritten; if (length > SSIZE_MAX) @throw [OFOutOfRangeException exception]; if ((bytesWritten = write(_handle, buffer, length)) < 0) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length bytesWritten: 0 errNo: errno]; #endif return (size_t)bytesWritten; } - (of_offset_t)lowlevelSeekToOffset: (of_offset_t)offset whence: (int)whence { of_offset_t ret; if (_handle == OF_INVALID_FILE_HANDLE) @throw [OFNotOpenException exceptionWithObject: self]; #ifndef OF_MORPHOS # if defined(OF_WINDOWS) ret = _lseeki64(_handle, offset, whence); # elif defined(OF_HAVE_OFF64_T) ret = lseek64(_handle, offset, whence); # else ret = lseek(_handle, offset, whence); # endif if (ret == -1) @throw [OFSeekFailedException exceptionWithStream: self offset: offset whence: whence errNo: errno]; #else switch (whence) { case SEEK_SET: ret = Seek64(_handle->handle, offset, OFFSET_BEGINNING); break; case SEEK_CUR: ret = Seek64(_handle->handle, offset, OFFSET_CURRENT); break; case SEEK_END: ret = Seek64(_handle->handle, offset, OFFSET_END); break; default: ret = -1; break; } if (ret == -1) @throw [OFSeekFailedException exceptionWithStream: self offset: offset whence: whence errNo: EINVAL]; #endif _atEndOfStream = false; return ret; } #ifdef OF_FILE_HANDLE_IS_FD - (int)fileDescriptorForReading { return _handle; } - (int)fileDescriptorForWriting { return _handle; } #endif - (void)close { if (_handle != OF_INVALID_FILE_HANDLE) closeHandle(_handle); _handle = OF_INVALID_FILE_HANDLE; [super close]; } - (void)dealloc { [self close]; [super dealloc]; } @end