diff --git a/mpw/mpw.cpp b/mpw/mpw.cpp index ca7b885..1fcb1e8 100644 --- a/mpw/mpw.cpp +++ b/mpw/mpw.cpp @@ -1,44 +1,170 @@ +#include +#include +#include + #include #include #include -#include -#include #include +#include #include #include #include #include +#include #include "mpw.h" - +#include "mpw_errno.h" namespace { using namespace MPW; + + int remap_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; + + } + + uint32_t ftrap_open(uint32_t name, uint32_t parm) + { + uint32_t d0; + int fd; + std::string sname; + + MPWFile f; + int nativeFlags; + std::memset(&f, 0, sizeof(f)); + + f.flags = memoryReadWord(parm); + + + nativeFlags = 0; + switch (f.flags & 0x03) + { + case 0x01: + nativeFlags = O_RDONLY; + break; + case 0x02: + nativeFlags = O_WRONLY; + break; + case 0x00: // ???? + case 0x03: + nativeFlags = O_RDWR; + break; + } + + if (f.flags & kO_APPEND) nativeFlags |= O_APPEND; + if (f.flags & kO_CREAT) nativeFlags |= O_CREAT; + if (f.flags & kO_TRUNC) nativeFlags |= O_TRUNC; + if (f.flags & kO_EXCL) nativeFlags |= O_EXCL; + + + const char *cp = (const char *)memoryPointer(name); + sname.assign(cp); + + if (f.flags & kO_RSRC) + sname.append(_PATH_RSRCFORKSPEC); + + if (f.flags & kO_CREAT) fd = ::open(sname.c_str(), nativeFlags, 0666); + else fd = ::open(sname.c_str(), nativeFlags); + + if (fd < 0) + { + d0 = 0x40000000 | remap_errno(errno); + f.error = -36; // ioErr ... whatever. + f.cookie = 0; + } + else + { + d0 = 0; + f.error = 0; + f.cookie = fd; + // todo -- keep a separate array of fd/counts for dup/close? + + // ... do I need to create the buffer? + } + + memoryWriteWord(f.error, parm + 2); + memoryWriteLong(f.cookie, parm + 8); + + return d0; + } + void ftrap_access(uint16_t trap) { // open a file, rename a file, or delete a file. + std::string sname; + uint32_t d0; uint32_t sp = cpuGetAReg(7); // hmmm not sure if 3 or 4 parameters. - - uint32_pt name = memoryReadLong(sp + 4); + + uint32_t name = memoryReadLong(sp + 4); uint32_t op = memoryReadLong(sp + 8); uint32_t parm = memoryReadLong(sp + 12); + fprintf(stderr, "%04x Access(%08x, %04x, %08x)\n", trap, name, op, parm); - MPWFile f; + switch (op) + { + case kF_OPEN: + d0 = ftrap_open(name, parm); + break; + default: + d0 = 0x40000000 | kEINVAL; + fprintf(stderr, "faccess - unsupported op %04x\n", op); + } - - fprintf(stderr, "%04x Access()\n", trap); - cpuSetDReg(0, 0); + cpuSetDReg(0, d0); } void ftrap_close(uint16_t trap) @@ -56,6 +182,8 @@ namespace { void ftrap_write(uint16_t trap) { + uint32_t d0; + uint32_t sp = cpuGetAReg(7); uint32_t parm = memoryReadLong(sp + 4); @@ -73,30 +201,52 @@ namespace { // hmmm how to handle crlf? + d0 = 0; if (f.count) { - std::unique_ptr buffer(new uint8_t[f.count]); - uint8_t *ptr = memoryPointer(f.buffer); - - - std::transform(ptr, ptr + f.count, buffer.get(), - [](uint8_t c) { return c == '\r' ? '\n' : c; } - ); + ssize_t size; int fd = f.cookie; - ::write(fd, buffer.get(), f.count); + if (f.flags & kO_BINARY) + { + size = ::write(fd, memoryPointer(f.buffer), f.count); + } + else + { + std::unique_ptr buffer(new uint8_t[f.count]); + uint8_t *ptr = memoryPointer(f.buffer); - // hmm, also needs to update the count actually transferred? + std::transform(ptr, ptr + f.count, buffer.get(), + [](uint8_t c) { return c == '\r' ? '\n' : c; } + ); + size = ::write(fd, buffer.get(), f.count); + } + + if (size < 0) + { + f.count = 0; + f.error = -36; // ioErr + d0 = 0x40000000 | remap_errno(errno); + } + else + { + f.count = size; + f.error = 0; + } + + // write back... + memoryWriteWord(f.error, parm + 2); + memoryWriteLong(f.count, parm + 12); } - cpuSetDReg(0, 0); + cpuSetDReg(0, d0); } void ftrap_ioctl(uint16_t trap) { // int ioctl(int fildes, unsigned int cmd, long *arg); - + uint32_t d0; uint32_t sp = cpuGetAReg(7); uint32_t fd = memoryReadLong(sp + 4); @@ -105,7 +255,11 @@ namespace { fprintf(stderr, "%04x IOCtl(%08x, %08x, %08x)\n", trap, fd, cmd, arg); - cpuSetDReg(0, 0); + // dup doesn't appear to dup so much as increment a refCount + // close decrements this refCount and doesn't close until it hits 0. + d0 = 0; + + cpuSetDReg(0, d0); } void ftrap_quit(uint16_t trap) diff --git a/mpw/mpw.h b/mpw/mpw.h index 4f21f5f..5bb9617 100644 --- a/mpw/mpw.h +++ b/mpw/mpw.h @@ -16,6 +16,47 @@ namespace MPW { uint32_t buffer; }; + // from MPW's FCntl.h + enum + { + kF_OPEN = (('d' << 8)| 0x00), + kF_DELETE = (('d' << 8) | 0x01), + kF_RENAME = (('d' << 8) | 0x02), + }; + + // from MPW's IOCtl.h + enum + { + kFIOLSEEK = (('f' << 8) | 0x00), /* Apple internal use only */ + kFIODUPFD = (('f' << 8) | 0x01), /* Apple internal use only */ + kFIOINTERACTIVE = (('f' << 8) | 0x02), /* If device is interactive */ + kFIOBUFSIZE = (('f' << 8) | 0x03), /* Return optimal buffer size */ + kFIOFNAME = (('f' << 8) | 0x04), /* Return filename */ + kFIOREFNUM = (('f' << 8) | 0x05), /* Return fs refnum */ + kFIOSETEOF = (('f' << 8) | 0x06), /* Set file length */ + }; + + enum + { + kSEEK_CUR = 1, + kSEEK_END = 2, + kSEEK_SET = 0, + }; + + enum + { + // despite these constants, 0x01 seems to be read, 0x02 is write, 0x03 is read/write. + kO_RDONLY = 0, /* Bits 0 and 1 are used internally */ + kO_WRONLY = 1, /* Values 0..2 are historical */ + kO_RDWR = 2, /* NOTE: it goes 0, 1, 2, *!* 8, 16, 32, ... */ + kO_APPEND = (1 << 3), /* append (writes guaranteed at the end) */ + kO_RSRC = (1 << 4), /* Open the resource fork */ + kO_CREAT = (1 << 8), /* Open with file create */ + kO_TRUNC = (1 << 9), /* Open with truncation */ + kO_EXCL = (1 << 10), /* w/ O_CREAT Exclusive "create-only" */ + kO_BINARY = (1 << 11), /* Open as a binary stream */ + }; + enum { fQuit = 0xf000, fAccess, diff --git a/mpw/mpw_errno.h b/mpw/mpw_errno.h new file mode 100644 index 0000000..118a356 --- /dev/null +++ b/mpw/mpw_errno.h @@ -0,0 +1,46 @@ +#ifndef __mpw_errno_h__ +#define __mpw_errno_h__ + +namespace MPW { + + // from MPW errno.h + enum { + kEPERM = 1, /* Permission denied */ + kENOENT = 2, /* No such file or directory */ + kENORSRC = 3, /* No such resource */ + kEINTR = 4, /* Interrupted system service */ + kEIO = 5, /* I/O error */ + kENXIO = 6, /* No such device or address */ + kE2BIG = 7, /* Argument list too long */ + kENOEXEC = 8, /* Exec format error */ + kEBADF = 9, /* Bad file number */ + kECHILD = 10, /* No children processes */ + kEAGAIN = 11, /* Resource temporarily unavailable, try again later */ + kENOMEM = 12, /* Not enough space */ + kEACCES = 13, /* Permission denied */ + kEFAULT = 14, /* Bad address */ + kENOTBLK = 15, /* Block device required */ + kEBUSY = 16, /* Device or resource busy */ + kEEXIST = 17, /* File exists */ + kEXDEV = 18, /* Cross-device link */ + kENODEV = 19, /* No such device */ + kENOTDIR = 20, /* Not a directory */ + kEISDIR = 21, /* Is a directory */ + kEINVAL = 22, /* Invalid argument */ + kENFILE = 23, /* File table overflow */ + kEMFILE = 24, /* Too many open files */ + kENOTTY = 25, /* Not a character device */ + kETXTBSY = 26, /* Text file busy */ + kEFBIG = 27, /* File too large */ + kENOSPC = 28, /* No space left on device */ + kESPIPE = 29, /* Illegal seek */ + kEROFS = 30, /* Read only file system */ + kEMLINK = 31, /* Too many links */ + kEPIPE = 32, /* Broken pipe */ + kEDOM = 33, /* Math arg out of domain of func */ + kERANGE = 34, /* Math result not representable */ + }; + +} + +#endif \ No newline at end of file