Merge branch 'PPCLink'

Fixes and support for the PPCLink utility.
This commit is contained in:
Kelvin Sherlock 2014-12-22 19:59:09 -05:00
commit 3dd91f18b6
22 changed files with 1084 additions and 325 deletions

View File

@ -577,6 +577,20 @@ namespace MacOS {
{
return std::error_condition(static_cast<int>(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 {

137
macos/tool_return.h Normal file
View File

@ -0,0 +1,137 @@
#ifndef __tool_return__
#define __tool_return__
#include "errors.h"
#include <utility>
namespace MacOS {
namespace internal {
class tool_return_base
{
protected:
macos_error _error;
tool_return_base() : _error(static_cast<macos_error>(0))
{}
tool_return_base(macos_error error) : _error(error)
{}
public:
macos_error error() const
{
return _error;
}
template<class... Args>
void throw_macos_error(Args&&... args) const
{
if (_error) MacOS::throw_macos_error(_error, std::forward<Args>(args)...);
}
};
} // namespace
template<class T>
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<class U>
T value_or(U&& u) const
{
if (_error) return u;
return _value;
}
template<class... Args>
T value_or_throw(Args&&... args) const
{
if (_error) throw_macos_error(std::forward<Args>(args)...);
return _value;
}
};
template<>
class tool_return<void> : 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

View File

@ -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)
{

View File

@ -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

View File

@ -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;
}

View File

@ -26,6 +26,7 @@
#include "mpw.h"
#include "mpw_internal.h"
#include "mpw_errno.h"
#include <algorithm>
#include <memory>
@ -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
{

View File

@ -52,7 +52,7 @@
#include <toolbox/os.h>
#include <toolbox/os_internal.h>
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;

View File

@ -22,6 +22,7 @@ set(TOOLBOX_SRC
pathnames.cpp
utility.cpp
fs_spec.cpp
realpath.c
)

View File

@ -73,7 +73,7 @@ namespace
// map of handle -> size [? just use Ptr map?]
std::map<uint32_t, HandleInfo> 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 pointers 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);
}
}

View File

@ -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);
}

View File

@ -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<std::chrono::steady_clock> when;
TimerEntry(uint32_t a, uint32_t b) : tmTaskPtr(a), tmAddr(b)
{}
};
// heap sorted by next task to run?
static std::deque<TimerEntry> 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;
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -65,6 +65,7 @@ namespace OS {
std::map<uint32_t, uint32_t> GestaltMap = {
{'alis', 1}, // Alias Manager
{'tmgr', 2}, // Time Manager (2 = revised, 3 = extended.)
};
uint16_t Gestalt(uint16_t trap)

View File

@ -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);

View File

@ -35,6 +35,8 @@
#include <sys/xattr.h>
#include <sys/stat.h>
#include <sys/paths.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
@ -48,14 +50,18 @@
#include <macos/errors.h>
#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)

View File

@ -41,38 +41,11 @@
#include <machine/endian.h>
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

View File

@ -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);

253
toolbox/realpath.c Normal file
View File

@ -0,0 +1,253 @@
/*
* Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
*
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
//#include "namespace.h"
#include <sys/param.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//#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);
}

View File

@ -43,6 +43,7 @@
#include <macos/sysequ.h>
#include <macos/errors.h>
#include <macos/tool_return.h>
#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<void> 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<int16_t> 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;

View File

@ -57,6 +57,9 @@ namespace RM
uint16_t Get1IndType(uint16_t trap);
uint16_t FSpOpenResFile(void);
uint16_t FSpCreateResFile(void);
}

View File

@ -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;