use new file abstraction.

This commit is contained in:
Kelvin Sherlock 2016-11-04 12:31:22 -04:00
parent cdd595a812
commit 9d16456b80
18 changed files with 691 additions and 574 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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