diff --git a/macos/errors.h b/macos/errors.h index f24845f..ff3f0f1 100644 --- a/macos/errors.h +++ b/macos/errors.h @@ -577,6 +577,20 @@ namespace MacOS { { return std::error_condition(static_cast(e), macos_system_category()); } + + inline void throw_macos_error(int e) + { + throw std::system_error(e, macos_system_category()); + } + inline void throw_macos_error(int e, const char *what) + { + throw std::system_error(e, macos_system_category(), what); + } + inline void throw_macos_error(int e, const std::string &what) + { + throw std::system_error(e, macos_system_category(), what); + } + } namespace std { diff --git a/macos/tool_return.h b/macos/tool_return.h new file mode 100644 index 0000000..52b9ce9 --- /dev/null +++ b/macos/tool_return.h @@ -0,0 +1,137 @@ +#ifndef __tool_return__ +#define __tool_return__ + +#include "errors.h" +#include + +namespace MacOS { + + namespace internal { + + class tool_return_base + { + protected: + macos_error _error; + + tool_return_base() : _error(static_cast(0)) + {} + + tool_return_base(macos_error error) : _error(error) + {} + + public: + + macos_error error() const + { + return _error; + } + + + template + void throw_macos_error(Args&&... args) const + { + if (_error) MacOS::throw_macos_error(_error, std::forward(args)...); + + } + + }; + } // namespace + + template + class tool_return : public internal::tool_return_base + { + private: + T _value; + + tool_return() = delete; + + operator T() const + { + return _value; + } + + public: + + tool_return(T value) : _value(value) + {} + + tool_return(macos_error error) : tool_return_base(error) + {} + + + tool_return &operator=(T value) + { + _value = value; + _error = 0; + return *this; + } + + tool_return &operator=(macos_error error) + { + _value = T(); + _error = error; + return *this; + } + + + constexpr const T* operator->() const + { + return &_value; + } + + + constexpr const T& operator *() const + { + return _value; + } + + + T value() const + { + return _value; + } + + template + T value_or(U&& u) const + { + if (_error) return u; + return _value; + } + + template + T value_or_throw(Args&&... args) const + { + if (_error) throw_macos_error(std::forward(args)...); + + return _value; + } + + + + + + }; + + template<> + class tool_return : public internal::tool_return_base + { + public: + + tool_return() + {} + + tool_return(macos_error error) : tool_return_base(error) + {} + + tool_return &operator=(macos_error error) + { + _error = error; + return *this; + } + + + }; + + +} // namespace IIgs +#endif diff --git a/mpw/mpw.cpp b/mpw/mpw.cpp index 7670252..7b3cbdc 100644 --- a/mpw/mpw.cpp +++ b/mpw/mpw.cpp @@ -73,52 +73,7 @@ namespace MPW bool Trace = false; - int errno_to_errno(int xerrno) - { - switch (xerrno) - { - case EPERM: return kEPERM; - case ENOENT: return kENOENT; - #ifdef ENORSRC - case ENORSRC: return kENORSRC; - #endif - - case EINTR: return kEINTR; - case EIO: return kEIO; - case ENXIO: return kENXIO; - case E2BIG: return kE2BIG; - case ENOEXEC: return kENOEXEC; - case EBADF: return kEBADF; - case ECHILD: return kECHILD; - case EAGAIN: return kEAGAIN; - case ENOMEM: return kENOMEM; - case EACCES: return kEACCES; - case EFAULT: return kEFAULT; - case ENOTBLK: return kENOTBLK; - case EBUSY: return kEBUSY; - case EEXIST: return kEEXIST; - case EXDEV: return kEXDEV; - case ENODEV: return kENODEV; - case ENOTDIR: return kENOTDIR; - case EISDIR: return kEISDIR; - case EINVAL: return kEINVAL; - case ENFILE: return kENFILE; - case EMFILE: return kEMFILE; - case ENOTTY: return kENOTTY; - case ETXTBSY: return kETXTBSY; - case EFBIG: return kEFBIG; - case ENOSPC: return kENOSPC; - case ESPIPE: return kESPIPE; - case EROFS: return kEROFS; - case EMLINK: return kEMLINK; - case EPIPE: return kEPIPE; - case EDOM: return kEDOM; - case ERANGE: return kERANGE; - } - return kEINVAL; - - } static bool isdir(const std::string &path) { diff --git a/mpw/mpw.h b/mpw/mpw.h index 94b0a6d..742765a 100644 --- a/mpw/mpw.h +++ b/mpw/mpw.h @@ -119,8 +119,6 @@ namespace MPW { void ftrap_write(uint16_t trap); void ftrap_ioctl(uint16_t trap); - // native errno to an MPW errno. - int errno_to_errno(int xerrno); } #endif \ No newline at end of file diff --git a/mpw/mpw_access.cpp b/mpw/mpw_access.cpp index f5a8f60..b7de0c2 100644 --- a/mpw/mpw_access.cpp +++ b/mpw/mpw_access.cpp @@ -133,7 +133,7 @@ namespace MPW Log(" delete(%s)\n", sname.c_str()); rv = ::unlink(sname.c_str()); - if (rv < 0) return 0x40000000 | errno_to_errno(errno); + if (rv < 0) return 0x40000000 | mpw_errno_from_errno(); return 0; } @@ -192,7 +192,7 @@ namespace MPW if (fd < 0) { // return an errno. - d0 = 0x40000000 | errno_to_errno(errno); + d0 = 0x40000000 | mpw_errno_from_errno(); f.error = MacOS::ioErr; f.cookie = 0; } diff --git a/mpw/mpw_io.cpp b/mpw/mpw_io.cpp index 1b5d00b..e48df99 100644 --- a/mpw/mpw_io.cpp +++ b/mpw/mpw_io.cpp @@ -26,6 +26,7 @@ #include "mpw.h" #include "mpw_internal.h" +#include "mpw_errno.h" #include #include @@ -81,7 +82,7 @@ namespace MPW { //f.count = 0; f.error = MacOS::ioErr; // ioErr - d0 = errno_to_errno(errno); + d0 = mpw_errno_from_errno(); } else { @@ -126,7 +127,7 @@ namespace MPW { //f.count = 0; f.error = MacOS::ioErr; // ioErr - d0 = errno_to_errno(errno); + d0 = mpw_errno_from_errno(); } else { diff --git a/mpw/mpw_ioctl.cpp b/mpw/mpw_ioctl.cpp index e8d1510..19ee9e6 100644 --- a/mpw/mpw_ioctl.cpp +++ b/mpw/mpw_ioctl.cpp @@ -52,7 +52,7 @@ #include #include - +using MacOS::macos_error_from_errno; namespace MPW @@ -335,8 +335,8 @@ namespace MPW off_t rv = ::lseek(fd, offset, nativeWhence); if (rv < 0) { - d0 = errno_to_errno(errno); - f.error = OS::Internal::errno_to_oserr(errno); + d0 = mpw_errno_from_errno(); + f.error = macos_error_from_errno(); //perror(NULL); } else @@ -375,8 +375,8 @@ namespace MPW [arg, &f](int fd, OS::Internal::FDEntry &e){ int ok = ftruncate(fd, arg); if (ok == 0) return 0; - f.error = OS::Internal::errno_to_oserr(errno); - return errno_to_errno(errno); + f.error = macos_error_from_errno(); + return (int)mpw_errno_from_errno(); }, [](int fd){ return kEINVAL; diff --git a/toolbox/CMakeLists.txt b/toolbox/CMakeLists.txt index 5412a4a..d4c9d3b 100644 --- a/toolbox/CMakeLists.txt +++ b/toolbox/CMakeLists.txt @@ -22,6 +22,7 @@ set(TOOLBOX_SRC pathnames.cpp utility.cpp fs_spec.cpp + realpath.c ) diff --git a/toolbox/mm.cpp b/toolbox/mm.cpp index 4069dd5..e7a7acb 100644 --- a/toolbox/mm.cpp +++ b/toolbox/mm.cpp @@ -73,7 +73,7 @@ namespace // map of handle -> size [? just use Ptr map?] std::map HandleMap; - inline uint16_t SetMemError(uint16_t error) + inline int16_t SetMemError(int16_t error) { memoryWriteWord(error, MacOS::MemErr); return error; @@ -284,9 +284,12 @@ namespace MM // todo -- size 0 should have a ptr to differentiate // from purged. - if (size) - { - ptr = (uint8_t *)mplite_malloc(&pool, size); + + // PPCLink calls NewHandle(0) but expects a valid pointer + // Assertion failed: *fHandle != NULL + //if (size) + //{ + ptr = (uint8_t *)mplite_malloc(&pool, size ? size : 1); if (!ptr) { HandleQueue.push_back(hh); @@ -296,7 +299,7 @@ namespace MM if (clear) std::memset(ptr, 0, size); - } + //} // need a handle -> ptr map? HandleMap.emplace(std::make_pair(hh, HandleInfo(mcptr, size))); @@ -394,6 +397,8 @@ namespace MM uint16_t SetHandleSize(uint32_t handle, uint32_t newSize) { + if (handle == 0) return SetMemError(MacOS::nilHandleErr); + const auto iter = HandleMap.find(handle); if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr); @@ -409,7 +414,14 @@ namespace MM // 1. - resizing to 0. if (!newSize) { - if (info.locked) return SetMemError(MacOS::memLockedErr); + if (info.locked) + { + //return SetMemError(MacOS::memLockedErr); + + // ppclink resizes locked handles. + info.size = 0; + return SetMemError(0); + } // todo -- size 0 should have a ptr to differentiate // from purged. @@ -562,6 +574,9 @@ namespace MM uint16_t BlockMove(uint16_t trap) { + // also implements BlockMoveData. + // BlockMove will flush caches, BlockMoveData will not. + /* * on entry: * A0 Pointer to source @@ -744,17 +759,9 @@ namespace MM SetMemError(0); - // find the pointer base... - // todo -- call lower bound, then iter-- ? - for (const auto & iter : PtrMap) - { - if (sp >= iter.first && sp < iter.first + iter.second) - { - return sp - iter.first; - } - } + // MemorySize is the top of the heap. stack is after it. - return 0; + return sp - MemorySize; } @@ -1037,9 +1044,21 @@ namespace MM * */ + /* + * The trap dispatcher sets the condition codes before returning + * from a trap by testing the low-order word of register D0 with + * a TST.W instruction. Because the block size returned in D0 by + * _GetHandleSize is a full 32-bit long word, the word-length + * test sets the condition codes incorrectly in this case. To + * branch on the contents of D0, use your own TST.L instruction + * on return from the trap to test the full 32 bits of the register. + */ + uint32_t hh = cpuGetAReg(0); - Log("%08x GetHandleSize(%08x)\n", trap, hh); + Log("%04x GetHandleSize(%08x)\n", trap, hh); + + if (hh == 0) return SetMemError(MacOS::nilHandleErr); // ???? auto iter = HandleMap.find(hh); @@ -1068,112 +1087,51 @@ namespace MM Log("%04x SetHandleSize(%08x, %08x)\n", trap, hh, newSize); return Native::SetHandleSize(hh, newSize); + } -#if 0 - auto iter = HandleMap.find(hh); + uint32_t RecoverHandle(uint16_t trap) + { + // FUNCTION RecoverHandle (p: Ptr): Handle; - if (iter == HandleMap.end()) return SetMemError(MacOS::memWZErr); - // todo -- if handle ptr is null, other logic? - // todo -- if locked, can't move. - - auto &info = iter->second; - - // 0 - no change in size. - if (info.size == newSize) return SetMemError(0); - - uint32_t mcptr = info.address; - uint8_t *ptr = mcptr + Memory; + /* + * on entry: + * A0 Master pointer + * + * on exit: + * A0 Handle to master pointer’s relocatable block + * D0 Unchanged + * + */ - // 1. - resizing to 0. - if (!newSize) + uint32_t p = cpuGetAReg(0); + uint32_t hh = 0; + + Log("%04x RecoverHandle(%08x)\n", trap, p); + + uint16_t error = MacOS::memBCErr; + for (const auto kv : HandleMap) { - if (info.locked) return SetMemError(MacOS::memLockedErr); + const HandleInfo &info = kv.second; - mplite_free(&pool, ptr); - info.address = 0; - info.size = 0; + if (!info.address) continue; - memoryWriteLong(info.address, hh); - return SetMemError(0); + uint32_t begin = info.address; + uint32_t end = info.address + info.size; + if (!info.size) end++; + if (p >= begin && p < end) + { + hh = kv.first; + error = MacOS::noErr; + break; + } } - // 2. - resizing from 0. + SetMemError(error); + cpuSetAReg(0, hh); - if (!mcptr) - { - if (info.locked) return SetMemError(MacOS::memLockedErr); - - ptr = (uint8_t *)mplite_malloc(&pool, newSize); - if (!ptr) return SetMemError(MacOS::memFullErr); - - mcptr = ptr - Memory; - info.address = mcptr; - info.size = newSize; - - memoryWriteLong(info.address, hh); - return SetMemError(0); - } - - for (unsigned i = 0; i < 2; ++i) - { - - // 3. - locked - if (info.locked) - { - if (mplite_resize(&pool, ptr, mplite_roundup(&pool, newSize)) == MPLITE_OK) - { - info.size = newSize; - return SetMemError(0); - } - } - else - { - - // 4. - resize. - - ptr = (uint8_t *)mplite_realloc(&pool, ptr, mplite_roundup(&pool, newSize)); - - if (ptr) - { - mcptr = ptr - Memory; - info.address = mcptr; - info.size = newSize; - - memoryWriteLong(info.address, hh); - return SetMemError(0); - } - - } - - fprintf(stderr, "mplite_realloc failed.\n"); - Native::PrintMemoryStats(); - - - if (i > 0) return SetMemError(MacOS::memFullErr); - - // purge... - for (auto & kv : HandleMap) - { - uint32_t handle = kv.first; - auto &info = kv.second; - - if (handle == hh) continue; - if (info.size && info.purgeable && !info.locked) - { - mplite_free(&pool, Memory + info.address); - info.size = 0; - info.address = 0; - - // also need to update memory - memoryWriteLong(0, handle); - } - } - - } - - return SetMemError(MacOS::memFullErr); -#endif + // return d0 register unchanged. + return cpuGetDReg(0); } @@ -1501,9 +1459,19 @@ namespace MM if (address) memoryWriteLong(0, address); ToolReturn<4>(sp, mplite_maxmem(&pool)); - SetMemError(0); // not sure if this is correct. oh well. - return 0; + return SetMemError(0); } + uint16_t TempFreeMem(void) + { + + // FUNCTION TempFreeMem: LongInt; + + Log(" TempFreeMem()\n"); + + ToolReturn<4>(-1, mplite_freemem(&pool)); + + return SetMemError(0); + } } diff --git a/toolbox/mm.h b/toolbox/mm.h index e15a728..ecb78be 100644 --- a/toolbox/mm.h +++ b/toolbox/mm.h @@ -59,6 +59,8 @@ namespace MM uint16_t SetHandleSize(uint16_t); uint16_t SetPtrSize(uint16_t); + uint32_t RecoverHandle(uint16_t); + uint16_t HGetState(uint16_t trap); uint16_t HLock(uint16_t trap); @@ -88,6 +90,7 @@ namespace MM // OS Dispatch uint16_t TempMaxMem(void); + uint16_t TempFreeMem(void); } diff --git a/toolbox/os.cpp b/toolbox/os.cpp index 4d76ee1..5454b25 100644 --- a/toolbox/os.cpp +++ b/toolbox/os.cpp @@ -52,11 +52,11 @@ #include "os_internal.h" #include "toolbox.h" #include "stackframe.h" - +#include "fs_spec.h" using ToolBox::Log; -using OS::Internal::errno_to_oserr; +using MacOS::macos_error_from_errno; namespace { @@ -288,7 +288,7 @@ namespace OS int rv = OS::Internal::FDEntry::close(ioRefNum, true); - if (rv < 0) d0 = errno_to_oserr(errno); + if (rv < 0) d0 = macos_error_from_errno(); else d0 = 0; memoryWriteWord(d0, parm + 16); @@ -324,7 +324,7 @@ namespace OS if (fd < 0) { - d0 = errno_to_oserr(errno); + d0 = macos_error_from_errno(); } else { @@ -339,6 +339,31 @@ namespace OS uint16_t Open(uint16_t trap) { + + enum { + /* IOParam */ + _qLink = 0, + _qType = 4, + _ioTrap = 6, + _ioCmdAddr = 8, + _ioCompletion = 12, + _ioResult = 16, + _ioNamePtr = 18, + _ioVRefNum = 22, + _ioRefNum = 24, + _ioVersNum = 26, + _ioPermssn = 27, + _ioMisc = 28, + _ioBuffer = 32, + _ioReqCount = 36, + _ioActCount = 40, + _ioPosMode = 44, + _ioPosOffset = 46, + + _ioDirID = 48, + + }; + uint32_t d0; int fd; @@ -348,25 +373,54 @@ namespace OS Log("%04x Open(%08x)\n", trap, parm); - uint32_t namePtr = memoryReadLong(parm + 18); + uint32_t namePtr = memoryReadLong(parm + _ioNamePtr); + uint32_t ioDirID = memoryReadLong(parm + _ioDirID); - uint8_t ioPermission = memoryReadByte(parm + 27); + uint8_t ioPermission = memoryReadByte(parm + _ioPermssn); std::string sname = ToolBox::ReadPString(namePtr, true); + sname = FSSpecManager::ExpandPath(sname, ioDirID); + + fd = Internal::FDEntry::open(sname, ioPermission, false); d0 = fd < 0 ? fd : 0; if (fd >= 0) { - memoryWriteWord(fd, parm + 24); + memoryWriteWord(fd, parm + _ioRefNum); } - memoryWriteWord(d0, parm + 16); + memoryWriteWord(d0, parm + _ioResult); return d0; } uint16_t OpenRF(uint16_t trap) { + + enum { + /* IOParam */ + _qLink = 0, + _qType = 4, + _ioTrap = 6, + _ioCmdAddr = 8, + _ioCompletion = 12, + _ioResult = 16, + _ioNamePtr = 18, + _ioVRefNum = 22, + _ioRefNum = 24, + _ioVersNum = 26, + _ioPermssn = 27, + _ioMisc = 28, + _ioBuffer = 32, + _ioReqCount = 36, + _ioActCount = 40, + _ioPosMode = 44, + _ioPosOffset = 46, + + _ioDirID = 48, + + }; + uint32_t d0; int fd; @@ -376,20 +430,22 @@ namespace OS Log("%04x OpenRF(%08x)\n", trap, parm); - uint32_t namePtr = memoryReadLong(parm + 18); + uint32_t namePtr = memoryReadLong(parm + _ioNamePtr); + uint32_t ioDirID = memoryReadLong(parm + _ioDirID); - uint8_t ioPermission = memoryReadByte(parm + 27); + uint8_t ioPermission = memoryReadByte(parm + _ioPermssn); std::string sname = ToolBox::ReadPString(namePtr, true); + sname = FSSpecManager::ExpandPath(sname, ioDirID); fd = Internal::FDEntry::open(sname, ioPermission, true); d0 = fd < 0 ? fd : 0; if (fd >= 0) { - memoryWriteWord(fd, parm + 24); + memoryWriteWord(fd, parm + _ioRefNum); } - memoryWriteWord(d0, parm + 16); + memoryWriteWord(d0, parm + _ioResult); return d0; } @@ -443,7 +499,7 @@ namespace OS } if (count < 0) { - d0 = errno_to_oserr(errno); + d0 = macos_error_from_errno(); } memoryWriteLong(pos, parm + 46); // new offset. @@ -499,7 +555,7 @@ namespace OS if (count < 0) { - d0 = errno_to_oserr(errno); + d0 = macos_error_from_errno(); } memoryWriteLong(pos, parm + 46); // new offset. @@ -536,7 +592,7 @@ namespace OS int ok = ::unlink(sname.c_str()); if (ok < 0) - d0 = errno_to_oserr(errno); + d0 = macos_error_from_errno(); else d0 = 0; @@ -560,7 +616,7 @@ namespace OS if (::fstat(ioRefNum, &st) < 0) { - d0 = errno_to_oserr(errno); + d0 = macos_error_from_errno(); size = 0; } else @@ -589,7 +645,7 @@ namespace OS int rv = ::ftruncate(ioRefNum, ioMisc); - d0 = rv < 0 ? errno_to_oserr(errno) : 0; + d0 = rv < 0 ? macos_error_from_errno() : 0; memoryWriteWord(d0, parm + 16); return d0; @@ -609,7 +665,7 @@ namespace OS int rv = ::lseek(ioRefNum, 0, SEEK_CUR); if (rv < 0) { - d0 = errno_to_oserr(errno); + d0 = macos_error_from_errno(); } else { @@ -768,7 +824,7 @@ namespace OS if (::stat(sname.c_str(), &st) < 0) { - d0 = errno_to_oserr(errno); + d0 = macos_error_from_errno(); memoryWriteWord(d0, parm + 16); return d0; @@ -871,7 +927,7 @@ namespace OS ok = ::stat(sname.c_str(), &st); if (ok < 0) { - d0 = errno_to_oserr(errno); + d0 = macos_error_from_errno(); memoryWriteWord(d0, parm + 16); return d0; } @@ -1197,4 +1253,182 @@ namespace OS return MacOS::prWrErr; } + #pragma mark - Timer + + struct TimerEntry { + uint32_t tmTaskPtr = 0; // address of the queue. passed back in A1. + uint32_t tmAddr = 0; + bool extended = false; + bool active = false; + + std::chrono::time_point when; + + TimerEntry(uint32_t a, uint32_t b) : tmTaskPtr(a), tmAddr(b) + {} + }; + + // heap sorted by next task to run? + static std::deque TimerQueue; + + namespace TMTask { + enum { + _qLink = 0, + _qType = 4, + _tmAddr = 6, + _tmCount = 10, + _tmWakeUp = 14, + _tmReserved = 18 + }; + } + + uint16_t InsTime(uint16_t trap) + { + // PROCEDURE InsTime (tmTaskPtr: QElemPtr); + + // this adds an entry to the queue but does not schedule it. + + /* + * on entry + * A0 Address of the task record + * + * on exit + * D0 Result code + */ + + using namespace TMTask; + + uint32_t tmTaskPtr = cpuGetAReg(0); + + Log("%04x InsTime(%08x)\n", trap, tmTaskPtr); + + if (tmTaskPtr) + { + memoryWriteLong(0, tmTaskPtr + _qLink); + memoryWriteWord(0, tmTaskPtr + _qType); + memoryWriteLong(0, tmTaskPtr + _tmCount); + memoryWriteLong(0, tmTaskPtr + _tmWakeUp); + memoryWriteLong(0, tmTaskPtr + _tmReserved); + + TimerQueue.emplace_back(tmTaskPtr, memoryReadLong(tmTaskPtr + _tmAddr)); + } + + return MacOS::noErr; + } + + uint16_t PrimeTime(uint16_t trap) + { + // PROCEDURE PrimeTime (tmTaskPtr: QElemPtr; count: LongInt); + // this activates an entry. + + /* + * on entry + * A0 Address of the task record + * D0 Specified delay time (long) + * + * on exit + * D0 Result code + */ + + using namespace TMTask; + + uint32_t tmTaskPtr = cpuGetAReg(0); + uint32_t count = cpuGetDReg(0); + + Log("%04x PrimeTime(%08x, %08x)\n", trap, tmTaskPtr, count); + + if (tmTaskPtr) + { + auto iter = std::find_if(TimerQueue.begin(), TimerQueue.end(), [tmTaskPtr](const TimerEntry &e){ + return e.tmTaskPtr == tmTaskPtr; + }); + + if (iter != TimerQueue.end() && !iter->active) + { + auto now = std::chrono::steady_clock::now(); + + iter->active = true; + + if (count == 0) { + // retain the original time or set it to now. + iter->when = std::max(now, iter->when); + } + else + { + int64_t micro; + if (count < 0x80000000) + micro = count * 1000; + else + micro = -(int32_t)count; + + + iter->when = now + std::chrono::microseconds(micro); + + } + memoryWriteWord(tmTaskPtr + _qType, 0x8000); + } + } + + + return MacOS::noErr; + + } + + uint16_t RmvTime(uint16_t trap) + { + // PROCEDURE RmvTime (tmTaskPtr: QElemPtr); + + // unschedule (but not actually remove) + + /* + * on entry + * A0 Address of the task record + * + * on exit + * D0 Result code + */ + + using namespace TMTask; + + uint32_t tmTaskPtr = cpuGetAReg(0); + + Log("%04x RmvTime(%08x)\n", trap, tmTaskPtr); + + if (tmTaskPtr) + { + auto iter = std::find_if(TimerQueue.begin(), TimerQueue.end(), [tmTaskPtr](const TimerEntry &e){ + return e.tmTaskPtr == tmTaskPtr; + }); + + if (iter != TimerQueue.end()) + { + uint32_t count = 0; + if (iter->active) + { + iter->active = false; + + + // update tmCount to the amount of time remaining. + // uses negative microseconds + // or positive milliseconds. + + auto now = std::chrono::steady_clock::now(); + + int64_t micro = std::chrono::duration_cast< std::chrono::microseconds >(iter->when - now).count(); + + if (micro < 0) + count = 0; + else if (micro < 0x80000000) + count = -micro; + else + count = micro / 10000; + } + + memoryWriteWord(tmTaskPtr + _qType, 0); + memoryWriteLong(tmTaskPtr + _tmCount, count); + } + } + + return MacOS::noErr; + } + } \ No newline at end of file diff --git a/toolbox/os.h b/toolbox/os.h index 4e75094..55b6c2a 100644 --- a/toolbox/os.h +++ b/toolbox/os.h @@ -9,11 +9,13 @@ namespace OS { enum { - fsCurPerm = 0, - fsRdPerm = 1, - fsWrPerm = 2, - fsRdWrPerm = 3, - fsRdWrShPerm = 4, + fsCurPerm = 0x00, + fsRdPerm = 0x01, + fsWrPerm = 0x02, + fsRdWrPerm = 0x03, + fsRdWrShPerm = 0x04, + fsRdDenyPerm = 0x10, + fsWrDenyPerm = 0x20 }; enum { @@ -98,6 +100,11 @@ namespace OS uint16_t ReadXPRam(uint16_t trap); uint16_t WriteXPRam(uint16_t trap); + uint16_t InsTime(uint16_t trap); + uint16_t InsXTime(uint16_t trap); + uint16_t PrimeTime(uint16_t trap); + uint16_t RmvTime(uint16_t trap); + } #endif diff --git a/toolbox/os_fileinfo.cpp b/toolbox/os_fileinfo.cpp index 7ada1e1..e193e7b 100644 --- a/toolbox/os_fileinfo.cpp +++ b/toolbox/os_fileinfo.cpp @@ -56,7 +56,7 @@ using ToolBox::Log; -using OS::Internal::errno_to_oserr; +using MacOS::macos_error_from_errno; @@ -155,7 +155,7 @@ namespace OS { if (::stat(sname.c_str(), &st) < 0) { - d0 = errno_to_oserr(errno); + d0 = macos_error_from_errno(); memoryWriteWord(d0, parm + _ioResult); return d0; @@ -279,7 +279,7 @@ namespace OS { ok = ::stat(sname.c_str(), &st); if (ok < 0) { - d0 = errno_to_oserr(errno); + d0 = macos_error_from_errno(); memoryWriteWord(d0, parm + _ioResult); return d0; } diff --git a/toolbox/os_gestalt.cpp b/toolbox/os_gestalt.cpp index affb36b..00ba179 100644 --- a/toolbox/os_gestalt.cpp +++ b/toolbox/os_gestalt.cpp @@ -65,6 +65,7 @@ namespace OS { std::map GestaltMap = { {'alis', 1}, // Alias Manager + {'tmgr', 2}, // Time Manager (2 = revised, 3 = extended.) }; uint16_t Gestalt(uint16_t trap) diff --git a/toolbox/os_hfs_dispatch.cpp b/toolbox/os_hfs_dispatch.cpp index a7aba7e..3b2d4da 100644 --- a/toolbox/os_hfs_dispatch.cpp +++ b/toolbox/os_hfs_dispatch.cpp @@ -55,7 +55,7 @@ using ToolBox::Log; -using OS::Internal::errno_to_oserr; +using MacOS::macos_error_from_errno; namespace OS { @@ -194,7 +194,7 @@ namespace OS { if (::stat(sname.c_str(), &st) < 0) { - d0 = errno_to_oserr(errno); + d0 = macos_error_from_errno(); memoryWriteWord(d0, parm + _ioResult); return d0; @@ -353,7 +353,7 @@ namespace OS { ok = ::stat(sname.c_str(), &st); if (ok < 0) { - d0 = errno_to_oserr(errno); + d0 = macos_error_from_errno(); memoryWriteWord(d0, parm + _ioResult); return d0; } @@ -396,6 +396,21 @@ namespace OS { } + uint16_t PBHOpenDeny(uint32_t paramBlock) + { + // AccessParam.ioDenyModes short word matches + // up with the permission byte considering it's big-endian. + + Log(" PBHOpenDeny\n"); + return OS::Open(0xa000); + } + + uint16_t PBHOpenRFDeny(uint32_t paramBlock) + { + Log(" PBHOpenRFDeny\n"); + return OS::OpenRF(0xa000); + } + uint16_t FSDispatch(uint16_t trap) { @@ -449,6 +464,12 @@ namespace OS { case 0x001a: return PBHOpenDF(paramBlock); + case 0x0038: + return PBHOpenDeny(paramBlock); + + case 0x0039: + return PBHOpenRFDeny(paramBlock); + default: fprintf(stderr, "HFSDispatch: selector %08x not implemented\n", selector); diff --git a/toolbox/os_highlevel.cpp b/toolbox/os_highlevel.cpp index 0ef432a..16cf86a 100644 --- a/toolbox/os_highlevel.cpp +++ b/toolbox/os_highlevel.cpp @@ -35,6 +35,8 @@ #include #include #include + + #include #include #include @@ -48,14 +50,18 @@ #include #include "os.h" +#include "rm.h" #include "os_internal.h" #include "toolbox.h" #include "stackframe.h" #include "fs_spec.h" using ToolBox::Log; -using OS::Internal::errno_to_oserr; +using MacOS::macos_error_from_errno; +extern "C" { + char * fs_spec_realpath(const char * __restrict path, char * __restrict resolved); +} namespace OS { @@ -71,6 +77,25 @@ namespace OS { // MacOS: -> { -1, 1, "MacOS" } // MacOS:dumper -> {-1, 2 "dumper"} + std::string realpath(const std::string &path) + { + char buffer[PATH_MAX + 1]; + + // FSSpecs are valid for non-existant files + // but not non-existant directories. + // realpath does not behave in such a manner. + + // expand the path. Also handles relative paths. + char *cp = ::fs_spec_realpath(path.c_str(), buffer); + if (!cp) + { + fprintf(stderr, "realpath failed %s\n", path.c_str()); + return ""; + } + + return std::string(cp); + } + uint16_t FSMakeFSSpec(void) { // FSMakeFSSpec(vRefNum: Integer; dirID: LongInt; fileName: Str255; VAR spec: FSSpec): OSErr; @@ -87,8 +112,6 @@ namespace OS { uint32_t spec; - - StackFrame<14>(vRefNum, dirID, fileName, spec); std::string sname = ToolBox::ReadPString(fileName, true); @@ -113,49 +136,38 @@ namespace OS { bool absolute = sname.length() ? sname[0] == '/' : false; if (absolute || (vRefNum == 0 && dirID == 0)) { - char buffer[PATH_MAX + 1]; - - // TODO -- FSSpecs are valid for non-existant files - // but not non-existant directories. - // realpath does not behave in such a manner. - - // expand the path. Also handles relative paths. - char *cp = realpath(sname.c_str(), buffer); - if (!cp) - { - std::memset(memoryPointer(spec), 0, 8); - return MacOS::mFulErr; - } std::string leaf; std::string path; + int parentID; - - path.assign(cp); - - // if sname is null then the target is the default directory... - // so this should be ok. + path = realpath(sname); + if (path.empty()) + { + std::memset(memoryPointer(spec), 0, 8); + return MacOS::mFulErr; + } int pos = path.find_last_of('/'); if (pos == path.npos) { - // ? should never happen... - std::swap(leaf, path); + // file is relative to cwd. + leaf = std::move(path); + parentID = 0; } else { leaf = path.substr(pos + 1); path = path.substr(0, pos + 1); // include the / + parentID = FSSpecManager::IDForPath(path, true); } - int parentID = FSSpecManager::IDForPath(path, true); memoryWriteWord(vRefNum, spec + 0); memoryWriteLong(parentID, spec + 2); // write the filename... ToolBox::WritePString(spec + 6, leaf); - // TODO -- return fnf if file does not exist. return 0; } @@ -177,6 +189,7 @@ namespace OS { uint32_t spec; uint32_t finderInfo; + uint16_t d0; StackFrame<8>(spec, finderInfo); @@ -190,9 +203,8 @@ namespace OS { Log(" FSpGetFInfo(%s, %08x)\n", path.c_str(), finderInfo); - - Internal::GetFinderInfo(path, memoryPointer(finderInfo), false); - return 0; + d0 = Internal::GetFinderInfo(path, memoryPointer(finderInfo), false); + return d0; } uint16_t FSpSetFInfo() @@ -201,7 +213,7 @@ namespace OS { uint32_t spec; uint32_t finderInfo; - uint16_t d0; + uint16_t d0 = 0; StackFrame<8>(spec, finderInfo); @@ -222,12 +234,19 @@ namespace OS { + uint16_t ResolveAliasFile() { + // FUNCTION ResolveAliasFile (VAR theSpec: FSSpec; + // resolveAliasChains: Boolean; + // VAR targetIsFolder: Boolean; + // VAR wasAliased: Boolean): OSErr; + uint32_t spec; uint16_t resolveAliasChains; uint32_t targetIsFolder; uint32_t wasAliased; + uint16_t d0 = 0; StackFrame<14>(spec, resolveAliasChains, targetIsFolder, wasAliased); @@ -238,23 +257,22 @@ namespace OS { path += leaf; - Log(" ResolveAliasFile(%s)\n", path.c_str()); + Log(" ResolveAliasFile(%s)\n", path.c_str()); struct stat st; int rv; rv = ::stat(path.c_str(), &st); - if (rv < 0) return errno_to_oserr(errno); + if (rv < 0) + return macos_error_from_errno(); if (targetIsFolder) - { - memoryWriteWord(S_ISDIR(st.st_mode) ? 1 : 0, targetIsFolder); - } + memoryWriteWord(S_ISDIR(st.st_mode) ? 1 : 0, targetIsFolder); // don't bother pretending a soft link is an alias. if (wasAliased) memoryWriteWord(0, wasAliased); - return 0; + return d0; } @@ -262,7 +280,26 @@ namespace OS { uint16_t HighLevelHFSDispatch(uint16_t trap) { + /* + * $0001 FSMakeFSSpec + * $0002 FSpOpenDF + * $0003 FSpOpenRF + * $0004 FSpCreate + * $0005 FSpDirCreate + * $0006 FSpDelete + * $0007 FSpGetFInfo + * $0008 FSpSetFInfo + * $0009 FSpSetFLock + * $000A FSpRstFLock + * $000B FSpRename + * $000C FSpCatMove + * $000D FSpOpenResFile + * $000E FSpCreateResFile + * $000F FSpExchangeFiles + */ + uint16_t selector; + uint16_t d0; selector = cpuGetDReg(0) & 0xffff; Log("%04x HighLevelHFSDispatch(%04x)\n", trap, selector); @@ -270,23 +307,34 @@ namespace OS { switch (selector) { case 0x0001: - return FSMakeFSSpec(); + d0 = FSMakeFSSpec(); break; case 0x0007: - return FSpGetFInfo(); + d0 = FSpGetFInfo(); break; case 0x0008: - return FSpSetFInfo(); + d0 = FSpSetFInfo(); + break; + + case 0x000d: + d0 = RM::FSpOpenResFile(); + break; + + case 0x000e: + d0 = RM::FSpCreateResFile(); break; default: - fprintf(stderr, "selector %04x not yet supported\n", selector); + fprintf(stderr, "HighLevelHFSDispatch selector %04x not yet supported\n", selector); exit(1); } + ToolReturn<2>(-1, d0); + return d0; + } uint16_t HGetVol(uint16_t trap) diff --git a/toolbox/os_internal.cpp b/toolbox/os_internal.cpp index 1b2fd43..3e77ca1 100644 --- a/toolbox/os_internal.cpp +++ b/toolbox/os_internal.cpp @@ -41,38 +41,11 @@ #include using ToolBox::Log; +using MacOS::macos_error_from_errno; namespace OS { namespace Internal { - uint16_t errno_to_oserr(int xerrno) - { - - switch (xerrno) - { - case 0: return 0; - case EBADF: return MacOS::rfNumErr; - case EIO: return MacOS::ioErr; - case EACCES: return MacOS::permErr; - case ENOENT: return MacOS::fnfErr; - case ENOTDIR: return MacOS::dirNFErr; - case EISDIR: return MacOS::notAFileErr; - case ENOTSUP: return MacOS::extFSErr; - case EROFS: return MacOS::wPrErr; - - case EEXIST: return MacOS::dupFNErr; - - case EBUSY: return MacOS::fBsyErr; - - case EDQUOT: return MacOS::dskFulErr; - case ENOSPC: return MacOS::dskFulErr; - - - default: - return MacOS::ioErr; - } - - } /* @@ -126,7 +99,7 @@ namespace OS { namespace Internal { { case ENOENT: case EACCES: - return errno_to_oserr(errno); + return macos_error_from_errno(); } // check for prodos ftype/auxtype @@ -268,7 +241,7 @@ namespace OS { namespace Internal { { case ENOENT: case EACCES: - return errno_to_oserr(errno); + return macos_error_from_errno(); } } std::memmove(buffer, info, 16); @@ -291,7 +264,7 @@ namespace OS { namespace Internal { } rv = ::setxattr(pathName.c_str(), XATTR_FINDERINFO_NAME, buffer, 32, 0, 0); - if (rv < 0) return errno_to_oserr(errno); + if (rv < 0) return macos_error_from_errno(); return 0; } @@ -318,7 +291,7 @@ namespace OS { namespace Internal { } rv = ::lseek(refNum, offset, mode); - if (rv < 0) return errno_to_oserr(errno); + if (rv < 0) return macos_error_from_errno(); return rv; } @@ -470,8 +443,14 @@ namespace OS { namespace Internal { if (filename.empty()) return MacOS::bdNamErr; int access = 0; + if (ioPermission != 0x33) ioPermission &= ~0x30; // drop deny read/write switch(ioPermission) { + case 0x33: + // PBHOpenDeny exclusive access. + access = O_RDWR | O_CREAT; // | O_EXCL; + break; + case fsWrPerm: case fsRdWrPerm: case fsRdWrShPerm: @@ -492,7 +471,7 @@ namespace OS { namespace Internal { Log(" open(%s, %04x)\n", xname.c_str(), access); - fd = ::open(xname.c_str(), access); + fd = ::open(xname.c_str(), access, 0666); if (fd < 0 && ioPermission == fsCurPerm && errno == EACCES) { fd = ::open(xname.c_str(), O_RDONLY); @@ -500,7 +479,7 @@ namespace OS { namespace Internal { if (fd < 0) { - return errno_to_oserr(errno); + return macos_error_from_errno(); } // allocate the fd entry diff --git a/toolbox/os_internal.h b/toolbox/os_internal.h index e30ed93..c9dbef3 100644 --- a/toolbox/os_internal.h +++ b/toolbox/os_internal.h @@ -6,8 +6,6 @@ namespace OS { namespace Internal { - uint16_t errno_to_oserr(int xerrno); - uint16_t GetFinderInfo(const std::string &pathname, void *info, bool extended); uint16_t SetFinderInfo(const std::string &pathname, void *info, bool extended); diff --git a/toolbox/realpath.c b/toolbox/realpath.c new file mode 100644 index 0000000..d104fc6 --- /dev/null +++ b/toolbox/realpath.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2003 Constantin S. Svintsoff + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)realpath.c 8.1 (Berkeley) 2/16/94"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD$"); + +//#include "namespace.h" +#include +#include + +#include +#include +#include +#include +//#include "un-namespace.h" + +#define FS_SPEC + +/* + * Find the real name of path, by removing all ".", ".." and symlink + * components. Returns (resolved) on success, or (NULL) on failure, + * in which case the path which caused trouble is left in (resolved). + */ + +#ifdef FS_SPEC +char * +fs_spec_realpath(const char * __restrict path, char * __restrict resolved) +#else +char * +realpath(const char * __restrict path, char * __restrict resolved) +#endif +{ + struct stat sb; + char *p, *q, *s; + size_t left_len, resolved_len; + unsigned symlinks; + int m, slen; + char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; + + #ifdef FS_SPEC + int serrno = errno; + #endif + + if (path == NULL) { + errno = EINVAL; + return (NULL); + } + if (path[0] == '\0') { + errno = ENOENT; + return (NULL); + } + if (resolved == NULL) { + resolved = malloc(PATH_MAX); + if (resolved == NULL) + return (NULL); + m = 1; + } else + m = 0; + symlinks = 0; + if (path[0] == '/') { + resolved[0] = '/'; + resolved[1] = '\0'; + if (path[1] == '\0') + return (resolved); + resolved_len = 1; + left_len = strlcpy(left, path + 1, sizeof(left)); + } else { + if (getcwd(resolved, PATH_MAX) == NULL) { + if (m) + free(resolved); + else { + resolved[0] = '.'; + resolved[1] = '\0'; + } + return (NULL); + } + resolved_len = strlen(resolved); + left_len = strlcpy(left, path, sizeof(left)); + } + if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { + if (m) + free(resolved); + errno = ENAMETOOLONG; + return (NULL); + } + + /* + * Iterate over path components in `left'. + */ + while (left_len != 0) { + /* + * Extract the next path component and adjust `left' + * and its length. + */ + p = strchr(left, '/'); + s = p ? p : left + left_len; + if (s - left >= sizeof(next_token)) { + if (m) + free(resolved); + errno = ENAMETOOLONG; + return (NULL); + } + memcpy(next_token, left, s - left); + next_token[s - left] = '\0'; + left_len -= s - left; + if (p != NULL) + memmove(left, s + 1, left_len + 1); + if (resolved[resolved_len - 1] != '/') { + if (resolved_len + 1 >= PATH_MAX) { + if (m) + free(resolved); + errno = ENAMETOOLONG; + return (NULL); + } + resolved[resolved_len++] = '/'; + resolved[resolved_len] = '\0'; + } + if (next_token[0] == '\0') { + /* Handle consequential slashes. */ + continue; + } + else if (strcmp(next_token, ".") == 0) + continue; + else if (strcmp(next_token, "..") == 0) { + /* + * Strip the last path component except when we have + * single "/" + */ + if (resolved_len > 1) { + resolved[resolved_len - 1] = '\0'; + q = strrchr(resolved, '/') + 1; + *q = '\0'; + resolved_len = q - resolved; + } + continue; + } + + /* + * Append the next path component and lstat() it. + */ + resolved_len = strlcat(resolved, next_token, PATH_MAX); + if (resolved_len >= PATH_MAX) { + if (m) + free(resolved); + errno = ENAMETOOLONG; + return (NULL); + } + if (lstat(resolved, &sb) != 0) { + #ifdef FS_SPEC + if (errno == ENOENT && p == NULL) { + errno = serrno; + return (resolved); + } + #endif + if (m) + free(resolved); + return (NULL); + } + if (S_ISLNK(sb.st_mode)) { + if (symlinks++ > MAXSYMLINKS) { + if (m) + free(resolved); + errno = ELOOP; + return (NULL); + } + slen = readlink(resolved, symlink, sizeof(symlink) - 1); + if (slen < 0) { + if (m) + free(resolved); + return (NULL); + } + symlink[slen] = '\0'; + if (symlink[0] == '/') { + resolved[1] = 0; + resolved_len = 1; + } else if (resolved_len > 1) { + /* Strip the last path component. */ + resolved[resolved_len - 1] = '\0'; + q = strrchr(resolved, '/') + 1; + *q = '\0'; + resolved_len = q - resolved; + } + + /* + * If there are any path components left, then + * append them to symlink. The result is placed + * in `left'. + */ + if (p != NULL) { + if (symlink[slen - 1] != '/') { + if (slen + 1 >= sizeof(symlink)) { + if (m) + free(resolved); + errno = ENAMETOOLONG; + return (NULL); + } + symlink[slen] = '/'; + symlink[slen + 1] = 0; + } + left_len = strlcat(symlink, left, + sizeof(symlink)); + if (left_len >= sizeof(left)) { + if (m) + free(resolved); + errno = ENAMETOOLONG; + return (NULL); + } + } + left_len = strlcpy(left, symlink, sizeof(left)); + } else if (!S_ISDIR(sb.st_mode) && p != NULL) { + if (m) + free(resolved); + errno = ENOTDIR; + return (NULL); + } + } + + /* + * Remove trailing slash except when the resolved pathname + * is a single "/". + */ + if (resolved_len > 1 && resolved[resolved_len - 1] == '/') + resolved[resolved_len - 1] = '\0'; + return (resolved); +} diff --git a/toolbox/rm.cpp b/toolbox/rm.cpp index 6d75edb..d419487 100644 --- a/toolbox/rm.cpp +++ b/toolbox/rm.cpp @@ -43,6 +43,7 @@ #include #include +#include #include "stackframe.h" #include "fs_spec.h" @@ -51,6 +52,10 @@ using ToolBox::Log; using namespace OS::Internal; using namespace ToolBox; +using MacOS::tool_return; +using MacOS::macos_error_from_errno; +using MacOS::macos_error; + namespace { @@ -101,6 +106,8 @@ namespace case 0x434f4445: // 'CODE' (Link) case 0x5041434b: // 'PACK' (PascalIIgs) case 0x4b4f4445: // 'KODE' (Link 32-bit Startup) + case 0x45525253: // 'ERRS' (PPCLink) + case 0x63667267: // 'cfrg' (PPCLink) return true; default: return false; @@ -398,6 +405,39 @@ namespace RM return SetResError(::ResError()); } + + tool_return CreateResFile(const std::string &path) + { + + if (path.empty()) return MacOS::paramErr; + + FSRef ref; + OSErr error; + int fd; + + error = ::FSPathMakeRef((const UInt8 *)path.c_str(), &ref, NULL); + if (error != noErr) + return macos_error(error); + + // FSCreateResourceFork only works with existing files. + + fd = ::open(path.c_str(), O_CREAT | O_EXCL | O_RDWR, 0666); + if (fd < 0) + { + if (errno != EEXIST) return macos_error_from_errno(); + } + if (fd >= 0) close(fd); + + + HFSUniStr255 fork = {0,{0}}; + ::FSGetResourceForkName(&fork); + + + error = ::FSCreateResourceFork(&ref, fork.length, fork.unicode, 0); + + return macos_error(error); + } + uint16_t CreateResFile(uint16_t trap) { // PROCEDURE CreateResFile (fileName: Str255); @@ -440,12 +480,12 @@ namespace RM fd = ::open(sname.c_str(), O_CREAT | O_EXCL | O_RDWR, 0666); if (fd < 0) { - if (errno != EEXIST) return SetResError(errno_to_oserr(errno)); + if (errno != EEXIST) return SetResError(macos_error_from_errno()); } if (fd >= 0) close(fd); - HFSUniStr255 fork = {0,{0}}; - ::FSGetResourceForkName(&fork); + HFSUniStr255 fork = {0,{0}}; + ::FSGetResourceForkName(&fork); error = ::FSCreateResourceFork(&ref, fork.length, fork.unicode, 0); @@ -453,17 +493,97 @@ namespace RM } + uint16_t FSpCreateResFile(void) + { + + // PROCEDURE FSpCreateResFile (spec: FSSpec; creator, fileType: OSType; scriptTag: ScriptCode); + + // creates the file, if necessary. + + uint32_t sp; + uint32_t spec; + uint32_t creator; + uint32_t fileType; + uint16_t scriptTag; + + sp = StackFrame<14>(spec, creator, fileType, scriptTag); + + + int parentID = memoryReadLong(spec + 2); + std::string sname = ToolBox::ReadPString(spec + 6, false); + + Log(" FSpCreateResFile(%s, %08x ('%s'), %08x ('%s'), %02x)\n", + sname.c_str(), + creator, ToolBox::TypeToString(creator).c_str(), + fileType, ToolBox::TypeToString(fileType).c_str(), + scriptTag); + + + sname = OS::FSSpecManager::ExpandPath(sname, parentID); + if (sname.empty()) + { + return SetResError(MacOS::dirNFErr); + } + + auto rv = CreateResFile(sname); + // returns errFSForkExists if fork already exists. + // therefore, if no error, set the ftype/ctype. + if (rv.error() == 0) + { + char buffer[32]; + std::memset(buffer, 0, sizeof(buffer)); + buffer[0] = fileType >> 24; + buffer[1] = fileType >> 16; + buffer[2] = fileType >> 8; + buffer[3] = fileType >> 0; + + buffer[4] = creator >> 24; + buffer[5] = creator >> 16; + buffer[6] = creator >> 8; + buffer[7] = creator >> 0; + + std::memcpy(buffer+4, &creator, 4); + OS::Internal::SetFinderInfo(sname, buffer, false); + } + + return SetResError(rv.error() == errFSForkExists ? 0 : rv.error()); + } + + + + + tool_return OpenResCommon(const std::string &path, uint16_t permission = 0) + { + OSErr error; + FSRef ref; + ResFileRefNum refNum; + + error = ::FSPathMakeRef( (const UInt8 *)path.c_str(), &ref, NULL); + if (error != noErr) + return (MacOS::macos_error)error; + + HFSUniStr255 fork = {0,{0}}; + ::FSGetResourceForkName(&fork); + + refNum = -1; + error = ::FSOpenResourceFile(&ref, + fork.length, + fork.unicode, + permission, + &refNum); + + if (error != noErr) + return (MacOS::macos_error)error; + + return refNum; + } + uint16_t OpenResFile(uint16_t trap) { // OpenResFile (fileName: Str255) : INTEGER; - ResFileRefNum refNum; - FSRef ref; - uint32_t sp; uint32_t fileName; - uint16_t permission; - OSErr error; sp = StackFrame<4>(fileName); @@ -471,27 +591,11 @@ namespace RM Log("%04x OpenResFile(%s)\n", trap, sname.c_str()); - error = ::FSPathMakeRef( (const UInt8 *)sname.c_str(), &ref, NULL); - if (error != noErr) - { - ToolReturn<2>(sp, (uint16_t)-1); - return SetResError(error); - } + auto rv = OpenResCommon(sname); - HFSUniStr255 fork = {0,{0}}; - ::FSGetResourceForkName(&fork); + ToolReturn<2>(sp, rv.value_or(-1)); - refNum = -1; - permission = 0; // whatever is allowed. - error = ::FSOpenResourceFile(&ref, - fork.length, - fork.unicode, - permission, - &refNum); - - ToolReturn<2>(sp, (uint16_t)refNum); - - return SetResError(error); + return SetResError(rv.error()); } uint16_t HOpenResFile(uint16_t trap) @@ -499,10 +603,6 @@ namespace RM // FUNCTION HOpenResFile (vRefNum: Integer; dirID: LongInt; // fileName: Str255; permission: SignedByte): Integer; - ResFileRefNum refNum; - FSRef ref; - OSErr error; - uint32_t sp; uint16_t vRefNum; @@ -525,34 +625,51 @@ namespace RM sname = OS::FSSpecManager::ExpandPath(sname, dirID); if (sname.empty()) { - error = MacOS::dirNFErr; ToolReturn<2>(sp, (uint16_t)-1); - return SetResError(error); + return SetResError(MacOS::dirNFErr); } - error = ::FSPathMakeRef( (const UInt8 *)sname.c_str(), &ref, NULL); - if (error != noErr) + auto rv = OpenResCommon(sname, permission); + + ToolReturn<2>(sp, rv.value_or(-1)); + + return SetResError(rv.error()); + } + + uint16_t FSpOpenResFile(void) + { + // FUNCTION FSpOpenResFile (spec: FSSpec; permission: SignedByte): Integer; + + uint32_t sp; + uint32_t spec; + uint16_t permission; + + sp = StackFrame<6>(spec, permission); + + + int parentID = memoryReadLong(spec + 2); + + std::string sname = ToolBox::ReadPString(spec + 6, false); + + Log(" FSpOpenResFile(%s, %04x)\n", sname.c_str(), permission); + + + sname = OS::FSSpecManager::ExpandPath(sname, parentID); + if (sname.empty()) { ToolReturn<2>(sp, (uint16_t)-1); - return SetResError(error); + return SetResError(MacOS::dirNFErr); } - HFSUniStr255 fork = {0,{0}}; - ::FSGetResourceForkName(&fork); + auto rv = OpenResCommon(sname, permission); - refNum = -1; - error = ::FSOpenResourceFile(&ref, - fork.length, - fork.unicode, - permission, - &refNum); + ToolReturn<2>(sp, rv.value_or(-1)); - ToolReturn<2>(sp, (uint16_t)refNum); - - return SetResError(0); + return SetResError(rv.error()); } + uint16_t OpenRFPerm(uint16_t trap) { // FUNCTION OpenRFPerm (fileName: Str255; vRefNum: Integer; diff --git a/toolbox/rm.h b/toolbox/rm.h index 8befbcb..a67d7f4 100644 --- a/toolbox/rm.h +++ b/toolbox/rm.h @@ -57,6 +57,9 @@ namespace RM uint16_t Get1IndType(uint16_t trap); + uint16_t FSpOpenResFile(void); + uint16_t FSpCreateResFile(void); + } diff --git a/toolbox/toolbox.cpp b/toolbox/toolbox.cpp index 60f9564..8208e37 100644 --- a/toolbox/toolbox.cpp +++ b/toolbox/toolbox.cpp @@ -65,6 +65,9 @@ namespace ToolBox { case 0x0015: return MM::TempMaxMem(); + case 0x0018: + return MM::TempFreeMem(); + default: fprintf(stderr, "OSDispatch: selector %04x not implemented\n", selector); @@ -223,7 +226,8 @@ namespace ToolBox { break; // BlockMove (sourcePtr,destPtr: Ptr; byteCount: Size); - case 0xa02e: + case 0xa02e: // BlockMove + case 0xa22e: // BlockMoveData d0 = MM::BlockMove(trap); break; @@ -285,6 +289,10 @@ namespace ToolBox { d0 = MM::HandleZone(trap); break; + case 0xa128: + d0 = MM::RecoverHandle(trap); + break; + // MaxApplZone case 0xa063: d0 = MM::MaxApplZone(trap); @@ -358,6 +366,19 @@ namespace ToolBox { d0 = MM::EmptyHandle(trap); break; + + case 0xa058: + d0 = OS::InsTime(trap); + break; + + case 0xa059: + d0 = OS::RmvTime(trap); + break; + + case 0xa05a: + d0 = OS::PrimeTime(trap); + break; + // resource manager stuff. // Count1Resources (theType: ResType): Integer;