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