diff --git a/mpw/CMakeLists.txt b/mpw/CMakeLists.txt index 270b619..68b4917 100644 --- a/mpw/CMakeLists.txt +++ b/mpw/CMakeLists.txt @@ -39,4 +39,6 @@ set_source_files_properties( "${CMAKE_CXX_FLAGS} -Wno-unused-variable" ) -add_library(MPW_LIB ${MPW_SRC}) \ No newline at end of file +add_library(MPW_LIB ${MPW_SRC}) + +target_link_libraries(MPW_LIB MACOS_LIB NATIVE_LIB) diff --git a/mpw/mpw.cpp b/mpw/mpw.cpp index ac8920f..ae3cc74 100644 --- a/mpw/mpw.cpp +++ b/mpw/mpw.cpp @@ -54,6 +54,8 @@ #include +#include + extern char **environ; @@ -74,6 +76,7 @@ namespace MPW bool Trace = false; + const std::string RootDir(); static bool isdir(const std::string &path) @@ -209,30 +212,24 @@ namespace MPW uint16_t Init(int argc, char **argv) { - /* - FDTable.resize(16); - FDTable[STDIN_FILENO] = 1; - FDTable[STDOUT_FILENO] = 1; - FDTable[STDERR_FILENO] = 1; - */ - /* - OS::Internal::FDTable.resize(3); - FDTable[STDIN_FILENO].refcount = 1; - FDTable[STDIN_FILENO].text = true; + // stdin/stdout/stderr + { + native::file_ptr io; - FDTable[STDOUT_FILENO].refcount = 1; - FDTable[STDOUT_FILENO].text = true; + io.reset(new native::fd_file("", STDIN_FILENO)); + io->text = true; + OS::Internal::open_file(std::move(io)); - FDTable[STDERR_FILENO].refcount = 1; - FDTable[STDERR_FILENO].text = true; - */ - - OS::Internal::FDEntry::allocate(STDIN_FILENO).text = true; - OS::Internal::FDEntry::allocate(STDOUT_FILENO).text = true; - OS::Internal::FDEntry::allocate(STDERR_FILENO).text = true; + io.reset(new native::fd_file("", STDOUT_FILENO)); + io->text = true; + OS::Internal::open_file(std::move(io)); + io.reset(new native::fd_file("", STDERR_FILENO)); + io->text = true; + OS::Internal::open_file(std::move(io)); + } std::string command = argv[0]; diff --git a/mpw/mpw_access.cpp b/mpw/mpw_access.cpp index cacf0cd..e7253ad 100644 --- a/mpw/mpw_access.cpp +++ b/mpw/mpw_access.cpp @@ -57,7 +57,7 @@ * may return an errno or an oserr, too, apparently. */ -/* 2016 update -- faccess chedks if the error (16-bit) is negative (tool error) +/* 2016 update -- faccess checks if the error (16-bit) is negative (tool error) * or positive (errno) and calls _uerror(errno, toolerr). toolerr is stored into * the MacOSErr variable and remapped to an errno. if toolerr == 0, errno is stored in * errno. @@ -165,7 +165,6 @@ namespace MPW uint32_t ftrap_open(uint32_t name, uint32_t parm) { uint32_t d0; - int fd; std::string sname; MPWFile f; @@ -203,12 +202,12 @@ namespace MPW // TODO -- can you create a resource file like this? - fd = native::open_fork(sname, f.flags & kO_RSRC, nativeFlags); + auto fd = native::open_fork(sname, f.flags & kO_RSRC, nativeFlags); - if (fd < 0) + if (!fd) { // return a tool error. - auto e = macos_error_from_errno(); + auto e = fd.error(); d0 = 0x40000000 | (uint16_t)e; /* | mpw_errno_from_errno(); */ f.error = (uint16_t)e; @@ -218,8 +217,9 @@ namespace MPW { d0 = 0; f.error = 0; - f.cookie = fd; + //f.cookie = fd; + native::file_ptr ff = std::move(fd).value(); // adjust the binary flags... // some apps are good about this but @@ -231,9 +231,16 @@ namespace MPW if (f.flags & kO_RSRC) f.flags |= kO_BINARY; + + ff->text = !(f.flags & kO_BINARY); + ff->resource = f.flags & kO_RSRC; + + f.cookie = OS::Internal::open_file(std::move(ff)); +/* auto &e = OS::Internal::FDEntry::allocate(fd, std::move(xname)); e.text = !(f.flags & kO_BINARY); e.resource = f.flags & kO_RSRC; +*/ } memoryWriteWord(f.flags, parm + 0); diff --git a/mpw/mpw_close.cpp b/mpw/mpw_close.cpp index c7a3efe..014d18d 100644 --- a/mpw/mpw_close.cpp +++ b/mpw/mpw_close.cpp @@ -49,9 +49,6 @@ namespace MPW void ftrap_close(uint16_t trap) { - // returns an mpw_errno - // close actually checks the error in the File Entry and converts that to unix. - // (sigh) uint32_t d0 = 0; @@ -67,61 +64,24 @@ namespace MPW f.count = memoryReadLong(parm + 12); f.buffer = memoryReadLong(parm + 16); + f.error = 0; + Log("%04x Close(%08x)\n", trap, parm); - if (!parm) - { - cpuSetDReg(0, kEINVAL); - return; - } - - int fd = f.cookie; - int rv = OS::Internal::FDEntry::close(fd); + Log(" close(%02x)\n", fd); - if (rv < 0) - { - f.error = MacOS::notOpenErr; - d0 = kEINVAL; - } - else - { - f.error = 0; - d0 = 0; + int rv = OS::Internal::close_file(fd); + + if (rv < 0) { + d0 = kEBADF; } -#if 0 - if (fd < 0 || fd >= OS::Internal::FDTable.size()) - { - f.error = OS::notOpenErr; - d0 = kEINVAL; - } - else - { - auto &e = OS::Internal::FDTable[fd]; - if (e.refcount == 0) - { - f.error = OS::notOpenErr; - d0 = kEINVAL; - } - else - { - if (--e.refcount == 0) - { - Log(" close(%02x)\n", fd); - ::close(fd); - } - f.error = 0; - d0 = 0; - } - } -#endif - memoryWriteWord(f.error, parm + 2); - cpuSetDReg(0, 0); + cpuSetDReg(0, d0); } diff --git a/mpw/mpw_io.cpp b/mpw/mpw_io.cpp index 2f15619..530fedc 100644 --- a/mpw/mpw_io.cpp +++ b/mpw/mpw_io.cpp @@ -53,7 +53,7 @@ namespace MPW void ftrap_read(uint16_t trap) { - uint32_t d0; + uint32_t d0 = 0; uint32_t sp = cpuGetAReg(7); uint32_t parm = memoryReadLong(sp + 4); @@ -67,27 +67,21 @@ namespace MPW f.count = memoryReadLong(parm + 12); f.buffer = memoryReadLong(parm + 16); + f.error = 0; Log("%04x Read(%08x)\n", trap, parm); - d0 = 0; int fd = f.cookie; - ssize_t size; Log(" read(%04x, %08x, %08x)", fd, f.buffer, f.count); - size = OS::Internal::FDEntry::read(fd, memoryPointer(f.buffer), f.count); - //Log(" -> %ld\n", size); - if (size < 0) - { - //f.count = 0; - f.error = MacOS::ioErr; // ioErr - d0 = mpw_errno_from_errno(); - } - else - { - f.count -= size; - f.error = 0; + auto ff = OS::Internal::find_file(fd); + if (ff) { + auto e = ff->read(memoryPointer(f.buffer), f.count); + f.count -= e.value_or(0); + d0 = f.error = e.error(); + } else { + d0 = kEBADF; } // write back... @@ -99,7 +93,7 @@ namespace MPW void ftrap_write(uint16_t trap) { - uint32_t d0; + uint32_t d0 = 0; uint32_t sp = cpuGetAReg(7); uint32_t parm = memoryReadLong(sp + 4); @@ -113,26 +107,21 @@ namespace MPW f.count = memoryReadLong(parm + 12); f.buffer = memoryReadLong(parm + 16); + f.error = 0; + Log("%04x Write(%08x)\n", trap, parm); - - d0 = 0; int fd = f.cookie; - ssize_t size; Log(" write(%04x, %08x, %08x)\n", fd, f.buffer, f.count); - size = OS::Internal::FDEntry::write(fd, memoryPointer(f.buffer), f.count); - if (size < 0) - { - //f.count = 0; - f.error = MacOS::ioErr; // ioErr - d0 = mpw_errno_from_errno(); - } - else - { - f.count -= size; - f.error = 0; + auto ff = OS::Internal::find_file(fd); + if (ff) { + auto e = ff->write(memoryPointer(f.buffer), f.count); + f.count -= e.value_or(0); + d0 = f.error = e.error(); + } else { + d0 = kEBADF; } // write back... diff --git a/mpw/mpw_ioctl.cpp b/mpw/mpw_ioctl.cpp index dac56e4..64b436e 100644 --- a/mpw/mpw_ioctl.cpp +++ b/mpw/mpw_ioctl.cpp @@ -59,7 +59,7 @@ namespace MPW uint32_t ftrap_dup(uint32_t parm, uint32_t arg) { - uint32_t d0; + uint32_t d0 = 0; MPWFile f; f.flags = memoryReadWord(parm); @@ -75,37 +75,13 @@ namespace MPW Log(" dup(%02x)\n", fd); - - d0 = OS::Internal::FDEntry::action(fd, - [](int fd, OS::Internal::FDEntry &e){ - e.refcount++; - return 0; - }, - [](int fd){ - return kEINVAL; - } - ); - - #if 0 - try - { - auto &e = OS::Internal::FDTable.at(fd); - - if (e.refcount) - { - d0 = 0; - fd.refcount++; - } - else - { - d0 = kEINVAL; - } + auto ff = OS::Internal::find_file(fd); + if (ff) { + ff->refcount++; } - catch(std::out_of_range &ex) - { - d0 = kEINVAL; + else { + d0 = kEBADF; } - #endif memoryWriteWord(f.error, parm + 2); return d0; @@ -116,6 +92,7 @@ namespace MPW // should return the preferred buffsize in *arg // an error will use the default size (0x400 bytes). + uint32_t d0 = 0; MPWFile f; f.flags = memoryReadWord(parm); @@ -131,18 +108,24 @@ namespace MPW Log(" bufsize(%02x)\n", fd); + auto ff = OS::Internal::find_file(fd); + if (ff) { + d0 = kEINVAL; + } else { + d0 = kEBADF; + } + memoryWriteWord(f.error, parm + 2); - return kEINVAL; + return d0; } uint32_t ftrap_interactive(uint32_t parm, uint32_t arg) { // return 0 if interactive, an error if - // non-interactive. - - uint32_t d0; + // non-interactive. arg is null. + uint32_t d0 = 0; MPWFile f; f.flags = memoryReadWord(parm); @@ -162,37 +145,13 @@ namespace MPW Log(" interactive(%02x)\n", fd); - d0 = OS::Internal::FDEntry::action(fd, - [](int fd, OS::Internal::FDEntry &e){ - int tty = ::isatty(fd); - return tty ? 0 : kEINVAL; - }, - [](int fd){ - return kEINVAL; - } - ); - -#if 0 - try - { - auto &e = OS::Internal::FDTable.at(fd); - - if (e.refcount) - { - int tty = ::isatty(fd); - d0 = tty ? 0 : kEINVAL; - } - else - { - d0 = kEINVAL; - } + auto ff = OS::Internal::find_file(fd); + if (!ff) { + d0 = kEBADF; + } else if (!ff->interactive()) { + f.error = d0 = MacOS::paramErr; } - catch(std::out_of_range &ex) - { - d0 = kEINVAL; - } -#endif memoryWriteWord(f.error, parm + 2); return d0; @@ -200,9 +159,11 @@ namespace MPW uint32_t ftrap_fname(uint32_t parm, uint32_t arg) { - // return file name. + // return file name (full path). // AsmIIgs uses this... + // arg is a c-string ptr. + uint32_t d0 = 0; MPWFile f; f.flags = memoryReadWord(parm); @@ -218,15 +179,22 @@ namespace MPW Log(" fname(%02x)\n", fd); + auto ff = OS::Internal::find_file(fd); + if (ff) { + f.error = d0 = MacOS::paramErr; + } else { + d0 = kEBADF; + } + memoryWriteWord(f.error, parm + 2); - return kEINVAL; + return d0; } uint32_t ftrap_refnum(uint32_t parm, uint32_t arg) { // returns the refnum in *arg - uint32_t d0; - + // on mpw, stdin/stdout/stderr return a param error. + uint32_t d0 = 0; MPWFile f; f.flags = memoryReadWord(parm); @@ -242,27 +210,13 @@ namespace MPW Log(" refnum(%02x)\n", fd); - d0 = OS::Internal::FDEntry::action(fd, - [arg](int fd, OS::Internal::FDEntry &e){ - memoryWriteWord(fd, arg); - return 0; - }, - [](int fd){ - return kEINVAL; - } - ); - -#if 0 - if (fd < 0 || fd >= FDTable.size() || !FDTable[fd]) - { - d0 = kEINVAL; + auto ff = OS::Internal::find_file(fd); + if (ff) { + if (ff->interactive()) f.error = d0 = MacOS::paramErr; + else memoryWriteWord(fd, arg); + } else { + d0 = kEBADF; } - else - { - d0 = 0; - memoryWriteWord(fd, arg); - } -#endif memoryWriteWord(f.error, parm + 2); return d0; @@ -272,8 +226,8 @@ namespace MPW uint32_t ftrap_lseek(uint32_t parm, uint32_t arg) { + uint32_t d0 = 0; MPWFile f; - uint32_t d0; uint32_t whence = memoryReadLong(arg); int32_t offset = memoryReadLong(arg + 4); // signed value. @@ -286,8 +240,8 @@ namespace MPW f.count = memoryReadLong(parm + 12); f.buffer = memoryReadLong(parm + 16); + f.error = 0; - int fd = f.cookie; /* * LinkIIgs does a seek on stdin. If it doesn't cause an @@ -316,33 +270,21 @@ namespace MPW return kEINVAL; } + int fd = f.cookie; Log(" lseek(%02x, %08x, %02x)\n", fd, offset, nativeWhence); - if (::isatty(fd)) - { - off_t rv = -1; - d0 = kEINVAL; - f.error = 0; - - memoryWriteLong(rv, arg + 4); - memoryWriteWord(f.error, parm + 2); - return d0; - - } - - off_t rv = ::lseek(fd, offset, nativeWhence); - if (rv < 0) - { - d0 = mpw_errno_from_errno(); - f.error = macos_error_from_errno(); - //perror(NULL); - } - else - { - d0 = 0; - f.error = 0; - } + off_t rv = - 1; + auto ff = OS::Internal::find_file(fd); + if (ff) { + MacOS::tool_return e(MacOS::noErr); + if (ff->interactive()) e = MacOS::paramErr; + else e = ff->seek(offset, nativeWhence); + rv = e.value_or(-1); + f.error = d0 = e.error(); + } else { + d0 = kEBADF; + } memoryWriteLong(rv, arg + 4); memoryWriteWord(f.error, parm + 2); @@ -353,8 +295,7 @@ namespace MPW uint32_t ftrap_seteof(uint32_t parm, uint32_t arg) { - uint32_t d0; - + uint32_t d0 = 0; MPWFile f; f.flags = memoryReadWord(parm); @@ -370,18 +311,15 @@ namespace MPW Log(" seteof(%02x, %08x)\n", fd, arg); - d0 = OS::Internal::FDEntry::action(fd, - [arg, &f](int fd, OS::Internal::FDEntry &e){ - int ok = ftruncate(fd, arg); - if (ok == 0) return 0; - f.error = macos_error_from_errno(); - return (int)mpw_errno_from_errno(); - }, - [](int fd){ - return kEINVAL; - } - ); - + auto ff = OS::Internal::find_file(fd); + if (ff) { + MacOS::tool_return e(MacOS::noErr); + if (ff->interactive()) e = MacOS::paramErr; + else e = ff->set_eof(arg); + f.error = d0 = e.error(); + } else { + d0 = kEBADF; + } memoryWriteWord(f.error, parm + 2); return d0; diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index 74aa8d9..58577fe 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -1,5 +1,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(NATIVE_SRC native.cpp ${CMAKE_SYSTEM_NAME}.cpp) +set(NATIVE_SRC native.cpp file.cpp ${CMAKE_SYSTEM_NAME}.cpp) add_library(NATIVE_LIB ${NATIVE_SRC}) +target_link_libraries(NATIVE_LIB MACOS_LIB) diff --git a/native/Darwin.cpp b/native/Darwin.cpp index e8f2472..ea07797 100644 --- a/native/Darwin.cpp +++ b/native/Darwin.cpp @@ -359,13 +359,20 @@ namespace native { } - int open_resource_fork(const std::string &path_name, int oflag) { + tool_return open_resource_fork(const std::string &path_name, int oflag) { std::string rname = path_name + _PATH_RSRCFORKSPEC; // todo -- verify behavior on non-hfs volume. //if ((oflag & O_ACCMODE) & O_WRONLY) oflag |= O_CREAT; - return open(rname.c_str(), oflag, 0666); + + int fd = open(rname.c_str(), oflag, 0666); + if (fd < 0) return macos_error_from_errno(); + + auto tmp = new fd_file(path_name, fd); + tmp->resource = true; + + return file_ptr(tmp); } diff --git a/native/Linux.cpp b/native/Linux.cpp index 9b3014f..39e1286 100644 --- a/native/Linux.cpp +++ b/native/Linux.cpp @@ -23,4 +23,197 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ - \ No newline at end of file + + +#define XATTR_FINDERINFO_NAME "user.apple.FinderInfo" +#define XATTR_RESOURCEFORK_NAME "user.apple.ResourceFork" + +#define XATTR_FILETYPE_NAME "user.prodos.FileType" +#define XATTR_AUXTYPE_NAME "user.prodos.AuxType" + +#include +#include +#include + +#include "file.h" +#include + +#include + +using MacOS::tool_return; +using MacOS::macos_error_from_errno; + +namespace { + + class xattr_file final : public file { + public: + xattr_file(int fd): _fd(fd); + ~xattr_file(); + + + tool_return read(void *out_buffer, size_t count) override; + tool_return write(void *in_buffer, size_t count) override; + tool_return get_mark() override; + tool_return set_mark(ssize_t new_mark) override; + tool_return get_eof() override; + tool_return set_eof(ssize_t new_eof) override; + + + private: + + ssize_t read_rfork(std::vector &buffer); + + int _fd = -1; + off_t _displacement = 0; + + }; + + xattr_file::~xattr_file() { + close(_fd); + } + + + ssize_t xattr_file::read_rfork(std::vector &buffer) { + ssize_t eof = -1; + buffer.clear(); + do { + eof = fgetxattr(_fd, XATTR_RESOURCEFORK_NAME, NULL, 0); + if (eof < 0) break; + buffer.resize(eof); + eof = fgetxattr(_fd, XATTR_RESOURCEFORK_NAME, buffer.data(), eof); + } while (eof < 0 && errno == ERANGE); + return eof; + } + + tool_return xattr_file::read(void *out_buffer, size_t count) { + std::vector buffer; + ssize_t size; + size = read_rfork(buffer); + if (size < 0) size = 0; + + if (_displacement >= buffer.size()) return 0; + + count = std::min(count, buffer.size() - _displacement); + std::copy_n(buffer.begin() + _displacement, count, (uint8_t *)out_buffer); + _displacement += count; + return count; + } + + + tool_return xattr_file::write(const void *in_buffer, size_t count) { + std::vector buffer; + ssize_t size; + size = read_rfork(buffer); + if (size < 0) size = 0; + + if (_displacement >= buffer.size()) { + buffer.resize(_displacement, 0); + } + if (_displacement + count >= buffer.size()) { + buffer.resize(_displacement + count, 0); + } + + std::copy_n((const uint8_t *)in_buffer, count, buffer.begin() + _displacement); + + int ok = fsetxattr(_fd, XATTR_RESOURCEFORK_NAME, buffer.data(), buffer.size(), 0); + if (ok < 0) return macos_error_from_errno(); + _displacement += count; + return count; + } + + + + tool_return xattr_file::get_mark() { + return _displacement; + } + + tool_return xattr_file::set_mark(ssize_t new_mark) { + if (new_mark < 0) return paramErr; + _displacement = new_mark; + } + + tool_return xattr_file::get_eof() { + ssize_t eof = fgetxattr(_fd, XATTR_RESOURCEFORK_NAME, NULL, 0); + if (eof < 0) eof = 0; + return eof; + } + + tool_return xattr_file::set_eof(ssize_t new_eof) { + + if (new_eof < 0) return paramErr; + + std::vector buffer; + + ssize_t eof = read_rfork(buffer); + if (eof < 0) eof = 0; + if (eof == new_eof) return noErr; + + buffer.resize(new_eof, 0); + int ok = fsetxattr(_fd, XATTR_RESOURCEFORK_NAME, buffer->data(), buffer.size(), 0); + if (ok < 0) return macos_error_from_errno(); + return noErr; + } + + +} + +namespace native { + + tool_return open_resource_fork(const std::string &path_name, int oflag) { + + int fd = open(rname.c_str(), oflag); + if (fd < 0) return macos_error_from_errno(); + return std::make_shared(fd); + } + + + + + + macos_error get_file_info(const std::string &path_name, file_info &fi) + { + struct stat st; + + if (stat(path_name.c_str(), &st) < 0) + return macos_error_from_errno(); + + fi.create_date = unix_to_mac(st.st_birthtime); + fi.modify_date = unix_to_mac(st.st_mtime); + fi.backup_date = 0; + + fi.attributes = 0; + + if (S_ISDIR(st.st_mode)) { + fi.type = file_info::directory; + fi.attributes = 1 << 4; + + int links = st.st_nlink - 2; + if (links < 0) links = 0; + if (links > 65535) links = 65535; + + fi.entry_count = links; + return noErr; + } + + // todo -- get actual block size instead of assuming 512. oh well! + + fi.type = file_info::file; + fi.data_logical_size = st.st_size; + fi.data_physical_size = (st.st_size + 511) & ~511; + fi.resource_physical_size = 0; + fi.resource_logical_size = 0; + + get_finder_info(path_name, fi.finder_info); + + ssize_t rsize = rforksize(path_name); + if (rsize > 0) { + fi.resource_physical_size = rsize; + fi.resource_logical_size = (rsize + 511) & ~511; + } + + return noErr; + } + + + +} \ No newline at end of file diff --git a/native/SunOS.cpp b/native/SunOS.cpp index 3c0802c..ebefcf9 100644 --- a/native/SunOS.cpp +++ b/native/SunOS.cpp @@ -202,13 +202,19 @@ namespace native { } - int open_resource_fork(const std::string &path_name, int oflag) { + tool_return open_resource_fork(const std::string &path_name, int oflag) { /* under HFS, every file has a resource fork. * Therefore, create it if opening for O_RDWR or O_WRONLY */ int mode = oflag & O_ACCMODE; if (mode == O_WRONLY || mode == O_RDWR) oflag |= O_CREAT; - return attropen(path_name.c_str(), XATTR_RESOURCEFORK_NAME, oflag, 0666); + int fd = attropen(path_name.c_str(), XATTR_RESOURCEFORK_NAME, oflag, 0666); + if (fd < 0) return macos_error_from_errno(); + + auto tmp = new fd_file(path_name, fd); + tmp->resource = true; + + return file_ptr(tmp); } diff --git a/native/native.cpp b/native/native.cpp index 652d3b7..2ff4e85 100644 --- a/native/native.cpp +++ b/native/native.cpp @@ -328,16 +328,21 @@ namespace native { } - int open_fork(const std::string &path_name, int fork, int oflag, int perm) { + tool_return open_fork(const std::string &path_name, int fork, int oflag, int perm) { - if (!fork) return ::open(path_name.c_str(), oflag, perm); + if (!fork) { + int fd = ::open(path_name.c_str(), oflag, perm); + if (fd < 0) return macos_error_from_errno(); + + return file_ptr(new fd_file(path_name, fd)); + } // if O_CREAT or E_EXCL, may need to create the file int tmp = oflag & (O_CREAT | O_EXCL); if (tmp) { int fd = ::open(path_name.c_str(), (oflag & O_ACCMODE) | tmp, perm); - if (fd < 0) return fd; + if (fd < 0) return macos_error_from_errno(); ::close(fd); oflag &= ~ (O_CREAT | O_EXCL); } diff --git a/native/native.h b/native/native.h index f626b7d..2ed2892 100644 --- a/native/native.h +++ b/native/native.h @@ -6,10 +6,14 @@ #include #include +#include + +#include "file.h" namespace native { using MacOS::macos_error; + using MacOS::tool_return; struct file_info { @@ -49,8 +53,8 @@ namespace native { - int open_fork(const std::string &path_name, int fork, int oflag, int perm = 0666); - int open_resource_fork(const std::string &path_name, int oflag); + tool_return open_fork(const std::string &path_name, int fork, int oflag, int perm = 0666); + tool_return open_resource_fork(const std::string &path_name, int oflag); } diff --git a/toolbox/CMakeLists.txt b/toolbox/CMakeLists.txt index 7bcac35..52fec09 100644 --- a/toolbox/CMakeLists.txt +++ b/toolbox/CMakeLists.txt @@ -50,3 +50,5 @@ set_source_files_properties( ) add_library(TOOLBOX_LIB ${TOOLBOX_SRC}) +target_link_libraries(TOOLBOX_LIB MACOS_LIB) +target_link_libraries(TOOLBOX_LIB NATIVE_LIB) diff --git a/toolbox/os.cpp b/toolbox/os.cpp index 47c0946..2ea898c 100644 --- a/toolbox/os.cpp +++ b/toolbox/os.cpp @@ -47,6 +47,9 @@ #include #include +#include +#include + #include "os.h" #include "os_internal.h" #include "toolbox.h" @@ -117,180 +120,6 @@ namespace OS return true; } -#if 0 - // known text file extensions - bool IsTextFile(const std::string &s) - { - - // 1. check for a TEXT file type. - { - int rv; - char buffer[32]; - - rv = ::getxattr(s.c_str(), XATTR_FINDERINFO_NAME, buffer, 32, 0, 0); - if (rv >= 8 && memcmp(buffer, "TEXT", 4) == 0) - return true; - } - - std::string ext = extension(s); - if (ext.empty()) return false; - - char c = ext[0]; - switch(c) - { - case 'a': - if (ext == "aii") // assembler - return true; - if (ext == "asm") - return true; - break; - - case 'c': - if (ext == "c") - return true; - if (ext == "cpp") - return true; - break; - - case 'e': - if (ext == "equ") // asm iigs include file. - return true; - if (ext == "equates") // asm iigs include file. - return true; - break; - - case 'i': - if (ext == "i") // asmiigs include file - return true; - if (ext == "inc") - return true; - break; - - case 'h': - if (ext == "h") // c header - return true; - break; - - case 'l': - if (ext == "lst") // asm iigs listing - return true; - break; - - case 'm': - if (ext == "macros") - return true; - break; - - case 'p': - if (ext == "p") // pascal - return true; - if (ext == "pas") // pascal - return true; - if (ext == "pii") // pascal - return true; - break; - - case 'r': - if (ext == "r") - return true; - if (ext == "rez") - return true; - if (ext == "rii") // rez - return true; - break; - - case 's': - if (ext == "src") // asm equates - return true; - break; - - } - - // check for e16.xxxx or m16.xxxx - ext = basename(s); - if (ext.length() > 4) - { - switch (ext[0]) - { - case 'm': - case 'M': - case 'e': - case 'E': - if (!strncmp("16.", ext.c_str() + 1, 3)) - return true; - break; - } - } - - return false; - } - - // known binary file extensions - bool IsBinaryFile(const std::string &s) - { - - // first -- check for a finder info extension. - { - uint8_t buffer[32]; - int rv; - - rv = ::getxattr(s.c_str(), XATTR_FINDERINFO_NAME, buffer, 32, 0, 0); - - if (rv >= 8 && ::memcmp(buffer + 4, "pdos",4) == 0) - { - // Bx__ ? - if (buffer[0] == 'B' && buffer[2] == ' ' && buffer[3] == ' ') - return true; - - // "p" $uv $wx $yz - if (buffer[0] == 'p') - { - uint8_t fileType = buffer[1]; - //uint16_t auxType = buffer[2] | (buffer[3] << 8); - - if (fileType >= 0xb1 && fileType <= 0xbf) - return true; - } - } - } - - std::string ext = extension(s); - if (ext.empty()) return false; - - char c = ext[0]; - switch(c) - { - case 'l': - if (ext == "lib") - return true; - break; - - case 'n': - // MrC / MrCpp temp file. - if (ext == "n") - return true; - // Newton C++ Tools output - if (ext == "ntkc") - return true; - break; - - case 'o': - if (ext == "o") - return true; - if (ext == "obj") - return true; - break; - - case 's': - // Newton C++ Intermediate file - if (ext == "sym") - return true; - break; - } - - return false; - } -#endif uint16_t Close(uint16_t trap) { @@ -303,8 +132,8 @@ namespace OS uint16_t ioRefNum = memoryReadWord(parm + 24); - int rv = OS::Internal::FDEntry::close(ioRefNum, true); - if (rv < 0) d0 = macos_error_from_errno(); + int rv = OS::Internal::close_file(ioRefNum, true); + if (rv < 0) d0 = MacOS::rfNumErr; else d0 = 0; memoryWriteWord(d0, parm + 16); @@ -418,9 +247,7 @@ namespace OS }; - uint32_t d0; - - int fd; + uint32_t d0 = 0; uint8_t ioPermission = memoryReadByte(parm + _ioPermssn); uint32_t namePtr = memoryReadLong(parm + _ioNamePtr); @@ -433,12 +260,9 @@ namespace OS sname = FSSpecManager::ExpandPath(sname, ioDirID); } - fd = Internal::FDEntry::open(sname, ioPermission, resource); - d0 = fd < 0 ? fd : 0; - if (fd >= 0) - { - memoryWriteWord(fd, parm + _ioRefNum); - } + auto fd = Internal::open_file(sname, resource, ioPermission); + if (fd) memoryWriteWord(fd.value(), parm + _ioRefNum); + d0 = fd.error(); memoryWriteWord(d0, parm + _ioResult); return d0; @@ -469,8 +293,7 @@ namespace OS uint16_t Read(uint16_t trap) { - uint32_t d0; - int32_t pos; + uint32_t d0 = 0; uint32_t parm = cpuGetAReg(0); Log("%04x Read(%08x)\n", trap, parm); @@ -483,6 +306,24 @@ namespace OS uint16_t ioPosMode = memoryReadWord(parm + 44); int32_t ioPosOffset = memoryReadLong(parm + 46); + Log(" read(%04x, %08x, %08x)\n", ioRefNum, ioBuffer, ioReqCount); + + /* + * per inside macintosh II-101: + * bit 6 (0x40) of ioPosOffset is used for read-verify operation + * (write date, call read w/ bit 6 to verify disk matches memory) + * returns ioError if it doesn't match. + * + * bit 7 (0x80) of ioPosMode indicate new-line mode is enabled -- + * bits 8-15 are a newline character. reading terminates when newline + * char is encountered (or eof or ioReqCount). + * + * bit 4 is please cache bit + * bit 5 is please don't cache bit + * (if neither or both set, no preference) + * + */ + if (ioReqCount < 0) { d0 = MacOS::paramErr; @@ -490,46 +331,48 @@ namespace OS return d0; } - pos = Internal::mac_seek(ioRefNum, ioPosMode, ioPosOffset); - if (pos < 0) - { - d0 = pos; - pos = 0; + if (ioPosMode & 0x80) { + fprintf(stderr, "Newline Read (eof char = %02x)\n", ioPosMode >> 8); + exit(1); + } - memoryWriteLong(pos, parm + 46); // new offset. + ssize_t offset = ioPosOffset; + int whence = ioPosMode; + uint32_t transferCount = 0; + + Internal::remap_seek(offset, whence); + + auto ff = Internal::find_file(ioRefNum); + if (!ff) { + d0 = MacOS::rfNumErr; memoryWriteWord(d0, parm + 16); return d0; } - Log(" read(%04x, %08x, %08x)\n", ioRefNum, ioBuffer, ioReqCount); - ssize_t count = OS::Internal::FDEntry::read(ioRefNum, memoryPointer(ioBuffer), ioReqCount); - if (count >= 0) - { - d0 = 0; - pos += count; - memoryWriteLong(count, parm + 40); + auto pos = ff->seek(offset, whence); + if (!pos) { + d0 = pos.error(); + memoryWriteWord(d0, parm + 16); + return d0; } - if (count == 0) - { - d0 = MacOS::eofErr; - } - if (count < 0) - { - d0 = macos_error_from_errno(); - } + auto xfer = ff->read(memoryPointer(ioBuffer), ioReqCount); + if (xfer && *xfer == 0) xfer = MacOS::eofErr; - memoryWriteLong(pos, parm + 46); // new offset. + d0 = xfer.error(); + transferCount = xfer.value_or(0); + offset = ff->get_mark().value_or(0ul); + + memoryWriteLong(offset, parm + 46); // new offset. + memoryWriteLong(transferCount, parm + 40); memoryWriteWord(d0, parm + 16); return d0; - } uint16_t Write(uint16_t trap) { - uint32_t d0; - int32_t pos; + uint32_t d0 = 0; uint32_t parm = cpuGetAReg(0); Log("%04x Write(%08x)\n", trap, parm); @@ -542,6 +385,8 @@ namespace OS uint16_t ioPosMode = memoryReadWord(parm + 44); int32_t ioPosOffset = memoryReadLong(parm + 46); + Log(" write(%04x, %08x, %08x)\n", ioRefNum, ioBuffer, ioReqCount); + if (ioReqCount < 0) { d0 = MacOS::paramErr; @@ -549,36 +394,37 @@ namespace OS return d0; } - pos = Internal::mac_seek(ioRefNum, ioPosMode, ioPosOffset); - if (pos < 0) - { - d0 = pos; - pos = 0; + ssize_t offset = ioPosOffset; + int whence = ioPosMode; + uint32_t transferCount = 0; - memoryWriteLong(pos, parm + 46); // new offset. + Internal::remap_seek(offset, whence); + + auto ff = Internal::find_file(ioRefNum); + if (!ff) { + d0 = MacOS::rfNumErr; memoryWriteWord(d0, parm + 16); return d0; - } - Log(" write(%04x, %08x, %08x)\n", ioRefNum, ioBuffer, ioReqCount); - ssize_t count = OS::Internal::FDEntry::write(ioRefNum, memoryPointer(ioBuffer), ioReqCount); - if (count >= 0) - { - d0 = 0; - pos += count; - memoryWriteLong(count, parm + 40); + auto pos = ff->seek(offset, whence); + if (!pos) { + d0 = pos.error(); + memoryWriteWord(d0, parm + 16); + return d0; } - if (count < 0) - { - d0 = macos_error_from_errno(); - } + auto xfer = ff->write(memoryPointer(ioBuffer), ioReqCount); + if (xfer && *xfer == 0) xfer = MacOS::eofErr; - memoryWriteLong(pos, parm + 46); // new offset. + d0 = xfer.error(); + transferCount = xfer.value_or(0); + offset = ff->get_mark().value_or(0ul); + + memoryWriteLong(offset, parm + 46); // new offset. + memoryWriteLong(transferCount, parm + 40); memoryWriteWord(d0, parm + 16); return d0; - } @@ -670,8 +516,8 @@ namespace OS uint16_t GetEOF(uint16_t trap) { - uint32_t d0; - size_t size; + uint32_t d0 = 0; + size_t size = 0; uint32_t parm = cpuGetAReg(0); @@ -680,18 +526,15 @@ namespace OS //uint32_t ioCompletion = memoryReadLong(parm + 12); uint16_t ioRefNum = memoryReadWord(parm + 24); - struct stat st; - - if (::fstat(ioRefNum, &st) < 0) - { - d0 = macos_error_from_errno(); + auto ff = Internal::find_file(ioRefNum); + if (ff) { + auto eof = ff->get_eof(); + d0 = eof.error(); + size = eof.value_or(0); + } else { + d0 = MacOS::rfNumErr; size = 0; } - else - { - d0 = 0; - size = st.st_size; - } memoryWriteWord(d0, parm + 16); memoryWriteLong(size, parm + 28); @@ -711,9 +554,14 @@ namespace OS uint16_t ioRefNum = memoryReadWord(parm + 24); uint32_t ioMisc = memoryReadLong(parm + 28); - int rv = ::ftruncate(ioRefNum, ioMisc); - d0 = rv < 0 ? macos_error_from_errno() : 0; + auto ff = Internal::find_file(ioRefNum); + if (ff) { + auto eof = ff->set_eof(ioMisc); + d0 = eof.error(); + } else { + d0 = MacOS::rfNumErr; + } memoryWriteWord(d0, parm + 16); return d0; @@ -721,7 +569,8 @@ namespace OS uint16_t GetFPos(uint16_t trap) { - uint32_t d0; + uint32_t d0 = 0; + size_t size = 0; uint32_t parm = cpuGetAReg(0); @@ -730,20 +579,23 @@ namespace OS //uint32_t ioCompletion = memoryReadLong(parm + 12); uint16_t ioRefNum = memoryReadWord(parm + 24); - int rv = ::lseek(ioRefNum, 0, SEEK_CUR); - if (rv < 0) - { - d0 = macos_error_from_errno(); - } - else - { - memoryWriteLong(0, parm + 36); // ioReqCount - memoryWriteLong(0, parm + 40); // ioActCount - memoryWriteWord(0, parm + 44); // ioPosMode - memoryWriteLong(rv, parm + 46); // ioPosOffset - d0 = 0; + + auto ff = Internal::find_file(ioRefNum); + if (ff) { + auto mark = ff->get_mark(); + d0 = mark.error(); + size = mark.value_or(0); + } else { + d0 = MacOS::rfNumErr; + size = 0; } + + memoryWriteLong(0, parm + 36); // ioReqCount + memoryWriteLong(0, parm + 40); // ioActCount + memoryWriteWord(0, parm + 44); // ioPosMode + memoryWriteLong(size, parm + 46); // ioPosOffset + memoryWriteWord(d0, parm + 16); return d0; } @@ -762,15 +614,23 @@ namespace OS int32_t ioPosOffset = memoryReadLong(parm + 46); - ioPosOffset = Internal::mac_seek(ioRefNum, ioPosMode, ioPosOffset); - d0 = 0; - if (ioPosOffset < 0) - { - d0 = ioPosOffset; - ioPosOffset = 0; + ssize_t offset = ioPosOffset; + int whence = ioPosMode; + + Internal::remap_seek(offset, whence); + + auto ff = Internal::find_file(ioRefNum); + if (ff) { + auto pos = ff->seek(offset, whence); + d0 = pos.error(); + offset = pos.value_or(0); + } else { + d0 = MacOS::rfNumErr; + offset = 0; } - memoryWriteLong(ioPosOffset, parm + 46); // new offset. + + memoryWriteLong(offset, parm + 46); // new offset. memoryWriteWord(d0, parm + 16); return d0; } diff --git a/toolbox/os_highlevel.cpp b/toolbox/os_highlevel.cpp index c26a336..fd18a7f 100644 --- a/toolbox/os_highlevel.cpp +++ b/toolbox/os_highlevel.cpp @@ -49,6 +49,8 @@ #include +#include + #include "os.h" #include "rm.h" #include "os_internal.h" @@ -211,12 +213,9 @@ namespace OS { return MacOS::dirNFErr; } - int fd = Internal::FDEntry::open(sname, permission, 0); - if (fd < 0) return fd; - - memoryWriteWord(fd, refNum); - - return 0; + auto fd = Internal::open_file(sname, 0, permission); + memoryWriteWord(fd.value_or(-1), refNum); + return fd.error(); } uint16_t FSpGetFInfo() diff --git a/toolbox/os_internal.cpp b/toolbox/os_internal.cpp index 84fa325..f0bd8a8 100644 --- a/toolbox/os_internal.cpp +++ b/toolbox/os_internal.cpp @@ -35,22 +35,26 @@ #include #include #include +#include #include #include #include #include +#include //#include using ToolBox::Log; using MacOS::macos_error_from_errno; +using MacOS::tool_return; +using MacOS::macos_error; namespace OS { namespace Internal { - +/* int32_t mac_seek(uint16_t refNum, uint16_t mode, int32_t offset) { off_t rv; @@ -75,7 +79,135 @@ namespace OS { namespace Internal { if (rv < 0) return macos_error_from_errno(); return rv; } +*/ + namespace { + std::vector file_table; + } + + int open_file(native::file_ptr &&f) { + + int fd = 0; + for (auto &ff : file_table) { + if (!ff) { + ff = std::move(f); + return fd; + } + ++fd; + } + + file_table.emplace_back(std::move(f)); + return fd; + } + + + + tool_return open_file(const std::string &name, int resource, int ioPermission) { + + + ioPermission &= 0x0f; + int oflag; + + switch(ioPermission) + { + case fsWrPerm: + oflag = O_WRONLY; + break; + case fsRdWrPerm: + case fsRdWrShPerm: + case fsCurPerm: + oflag = O_RDWR; + break; + case fsRdPerm: + oflag = O_RDONLY; + break; + default: + return MacOS::paramErr; + break; + } + + + auto ff = native::open_fork(name, resource, oflag); + if (ff.error() == MacOS::permErr && ioPermission == fsCurPerm) + ff = native::open_fork(name, resource, O_RDONLY); + + + if (!ff) return ff.error(); + + auto f = std::move(ff).value(); + f->resource = resource; + f->text = resource ? false : native::is_text_file(name); + + return open_file(std::move(f)); + } + + + + + + + + + + int close_file(int fd, bool force) { + if (fd < 0 || fd >= file_table.size()) return -1; + auto &f = file_table[fd]; + if (!f) return -1; + if (force || --f->refcount == 0) f.reset(); + return 0; + } + + native::file *find_file(int fd) { + if (fd < 0 || fd >= file_table.size()) return nullptr; + return file_table[fd].get(); + } + + + macos_error remap_iopermission(int ioPermission) { + switch(ioPermission & 0x0f) + { + case fsWrPerm: + case fsRdWrPerm: + case fsRdWrShPerm: + case fsCurPerm: + ioPermission = O_RDWR; + return MacOS::noErr; + break; + case fsRdPerm: + ioPermission = O_RDONLY; + return MacOS::noErr; + break; + default: + ioPermission = O_RDWR; + return MacOS::paramErr; + break; + } + } + + + macos_error remap_seek(ssize_t &offset, int &mode) { + + switch (mode & 0x03) + { + case OS::fsAtMark: + mode = SEEK_CUR; + offset = 0; + break; + case OS::fsFromStart: + mode = SEEK_SET; + break; + case OS::fsFromLEOF: + mode = SEEK_END; + break; + case OS::fsFromMark: + mode = SEEK_CUR; + break; + } + + return MacOS::noErr; + } + +#if 0 //std::deque FDTable; std::deque FDEntry::FDTable; @@ -264,5 +396,5 @@ namespace OS { namespace Internal { return fd; } - +#endif } } diff --git a/toolbox/os_internal.h b/toolbox/os_internal.h index c067a55..6db1148 100644 --- a/toolbox/os_internal.h +++ b/toolbox/os_internal.h @@ -5,17 +5,43 @@ #include #include +#include + namespace OS { std::string realpath(const std::string &path); namespace Internal { - - int32_t mac_seek(uint16_t refNum, uint16_t mode, int32_t offset); + using MacOS::tool_return; + + //int32_t mac_seek(uint16_t refNum, uint16_t mode, int32_t offset); + + MacOS::macos_error remap_iopermission(int ioPermission); + MacOS::macos_error remap_seek(ssize_t &offset, int &mode); + + + int open_file(native::file_ptr &&f); + + tool_return open_file(const std::string &name, int fork, int permission); + + int close_file(int fd, bool force = false); + native::file *find_file(int fd); + +#if 0 + template + macos_error with_file(int fd, FX fx) { + if (fd < 0 || fd >= FDTable.size()) return MacOS::rfNumErr; + auto &e = FDTable[fd]; + if (!e) return MacOS::rfNumErr; + return fx(e); + } +#endif + +#if 0 struct FDEntry { int refcount; @@ -65,6 +91,7 @@ namespace Internal { } }; +#endif } } diff --git a/toolbox/rm-new.cpp b/toolbox/rm-new.cpp index 12139f4..e805f13 100644 --- a/toolbox/rm-new.cpp +++ b/toolbox/rm-new.cpp @@ -24,6 +24,10 @@ * */ +/* + * TODO - https://www.fenestrated.net/mirrors/Apple%20Technotes%20(As%20of%202002)/tn/tn1120.html + * Opening Files Twice Considered Hard + */ #include "rm.h" #include "mm.h" @@ -50,6 +54,7 @@ #include #include +#include #include #include "stackframe.h" @@ -174,7 +179,7 @@ struct resource { struct resource_file { resource_file *next = nullptr; - int fd = -1; + native::file_ptr file; int refnum = -1; @@ -197,9 +202,7 @@ struct resource_file { resource_file &operator=(const resource_file &) = delete; resource_file &operator=(resource_file &&) = delete; - ~resource_file() { - if (fd >= 0) close(fd); - } + ~resource_file() = default; }; @@ -419,23 +422,22 @@ namespace { tool_return get_resource_size(resource_file &rf, resource &r) { uint8_t buffer[4]; - if (lseek(rf.fd, rf.offset_rdata + r.data_offset, SEEK_SET) < 0) - return macos_error_from_errno(); - size_t ok = read(rf.fd, buffer, sizeof(buffer)); - if (ok != 4) return mapReadErr; + auto sm = rf.file->set_mark(rf.offset_rdata + r.data_offset); + if (sm.error()) return sm.error(); + + auto ok = rf.file->read(buffer, sizeof(buffer)); + if (ok.value_or(0) != 4) return mapReadErr; return r.disk_size = read_32(buffer); - } tool_return read_resource_map(resource_file &rf) { - ssize_t ok; uint8_t header[100]; - ok = read(rf.fd, header, sizeof(header)); - if (ok != sizeof(header)) return mapReadErr; + auto ok = rf.file->read(header, sizeof(header)); + if (ok.value_or(0) != sizeof(header)) return mapReadErr; rf.offset_rdata = read_32(header+0); rf.offset_rmap = read_32(header+4); @@ -445,9 +447,11 @@ namespace { if (rf.length_rmap < 30) return mapReadErr; std::vector rmap(rf.length_rmap); - if (lseek(rf.fd, rf.offset_rmap, SEEK_SET) < 0) return macos_error_from_errno(); - ok = read(rf.fd, rmap.data(), rf.length_rmap); - if (ok != rf.length_rmap) return mapReadErr; + auto sm = rf.file->set_mark(rf.offset_rmap); + if (sm.error()) return sm.error(); + + ok = rf.file->read(rmap.data(), rf.length_rmap); + if (ok.value_or(0) != rf.length_rmap) return mapReadErr; rf.attr = read_16(rmap, 22, std::nothrow); uint16_t offset_type_list = read_16(rmap, 24, std::nothrow); @@ -507,7 +511,6 @@ namespace { } tool_return load_resource(resource_file &rf, resource &r) { - ssize_t ok; uint32_t handle = r.handle; //if (!handle) return resNotFound; @@ -529,15 +532,14 @@ namespace { if (r.attr & resLocked) attr |= MM::attrLocked; - ok = read(rf.fd, memoryPointer(*ptr), *size); - if (ok < 0) { - auto rv = macos_error_from_errno(); + auto ok = rf.file->read(memoryPointer(*ptr), *size); + if (ok.error()) { // ??? MM::Native::EmptyHandle(handle); - return rv; + return ok.error(); } - if (ok != *size) { + if (ok.value() != *size) { MM::Native::EmptyHandle(handle); return mapReadErr; } @@ -549,8 +551,6 @@ namespace { tool_return read_resource(resource_file &rf, resource &r) { - ssize_t ok; - if (r.handle) return r.handle; @@ -574,14 +574,13 @@ namespace { auto hh = MM::Native::NewHandleWithAttr(*size, attr); if (hh.error()) return hh.error(); - ok = read(rf.fd, memoryPointer(hh->pointer), *size); - if (ok < 0) { - auto rv = macos_error_from_errno(); + auto ok = rf.file->read(memoryPointer(hh->pointer), *size); + if (ok.error()) { MM::Native::DisposeHandle(hh->handle); - return rv; + return ok.error(); } - if (ok != *size) { + if (*ok != *size) { MM::Native::DisposeHandle(hh->handle); return mapReadErr; } @@ -614,10 +613,10 @@ namespace { } uint32_t xx = htobe32(hi->size); - lseek(rf.fd, rf.offset_rdata + r.data_offset, SEEK_SET); - write(rf.fd, &xx, 4); + rf.file->set_mark(rf.offset_rdata + r.data_offset); + rf.file->write(&xx, 4); // todo -- if purged, is size 0?? - write(rf.fd, memoryPointer(hi->address), hi->size); + rf.file->write(memoryPointer(hi->address), hi->size); rf.attr &= ~resChanged; return noErr; @@ -719,12 +718,13 @@ namespace Native { tool_return OpenResFile(const std::string &path_name, uint16_t perm) { - int fd = native::open_resource_fork(path_name, O_RDONLY); - if (fd < 0) return SetResError(macos_error_from_errno()); + auto fd = native::open_resource_fork(path_name, O_RDONLY); + if (fd.error()) return SetResError(fd.error()); auto rf = std::make_unique(); - rf->fd = fd; + rf->file = std::move(fd).value(); + rf->file->resource = true; rf->attr |= mapReadOnly; auto rv = read_resource_map(*rf); if (!rv) return SetResError(rv.error()); @@ -838,38 +838,26 @@ namespace Native { if (path.empty()) return SetResError(MacOS::bdNamErr); - struct stat st; macos_error err = noErr; - int fd = native::open_fork(path, 0, O_CREAT | O_EXCL | O_WRONLY, 0666); - if (fd < 0) { - if (errno == EEXIST) err = dupFNErr; - else return SetResError(macos_error_from_errno()); + auto fd = native::open_fork(path, 0, O_CREAT | O_EXCL | O_WRONLY, 0666); + if ((err = fd.error())) { + if (err != dupFNErr) return SetResError(err); } - close(fd); fd = native::open_fork(path, 1, O_WRONLY, 0666); - if (fd < 0) return SetResError(macos_error_from_errno()); + if (fd.error()) return SetResError(macos_error_from_errno()); + + auto ff = std::move(fd).value(); // need to check if resource fork size > 0 -- don't clobber an existing fork. - if (fstat(fd, &st) < 0) { - auto rv = macos_error_from_errno(); - close(fd); - return SetResError(rv); - } - if (st.st_size > 0) { - close(fd); - return SetResError(err); + if (ff->get_eof().value()) { + return SetResError(err); } - ssize_t ok = write(fd, empty_resource_fork, sizeof(empty_resource_fork)); - if (ok != sizeof(empty_resource_fork)) { - auto rv = macos_error_from_errno(); - close(fd); - return SetResError(rv); - } + auto ok = ff->write(empty_resource_fork, sizeof(empty_resource_fork)); + if (ok.error()) return SetResError(ok.error()); - close(fd); return SetResError(err); }