mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-12-30 20:29:26 +00:00
2282 lines
67 KiB
C++
2282 lines
67 KiB
C++
/*
|
|
* extfs.cpp - MacOS file system for native file system access
|
|
*
|
|
* Basilisk II (C) 1997-2008 Christian Bauer
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/*
|
|
* SEE ALSO
|
|
* Guide to the File System Manager (from FSM 1.2 SDK)
|
|
*
|
|
* TODO
|
|
* LockRng
|
|
* UnlockRng
|
|
* (CatSearch)
|
|
* (MakeFSSpec)
|
|
* (GetVolMountInfoSize)
|
|
* (GetVolMountInfo)
|
|
* (GetForeignPrivs)
|
|
* (SetForeignPrivs)
|
|
*/
|
|
|
|
#include "sysdeps.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
|
|
#ifndef WIN32
|
|
#include <unistd.h>
|
|
#include <dirent.h>
|
|
#endif
|
|
|
|
#if defined __APPLE__ && defined __MACH__
|
|
#include <sys/attr.h>
|
|
#endif
|
|
|
|
#include "cpu_emulation.h"
|
|
#include "emul_op.h"
|
|
#include "main.h"
|
|
#include "disk.h"
|
|
#include "prefs.h"
|
|
#include "user_strings.h"
|
|
#include "extfs.h"
|
|
#include "extfs_defs.h"
|
|
|
|
#ifdef WIN32
|
|
# include "posix_emu.h"
|
|
#endif
|
|
|
|
#define DEBUG 0
|
|
#include "debug.h"
|
|
|
|
|
|
// File system global data and 68k routines
|
|
enum {
|
|
fsCommProcStub = 0,
|
|
fsHFSProcStub = 6,
|
|
fsDrvStatus = 12, // Drive Status record
|
|
fsFSD = 42, // File system descriptor
|
|
fsPB = 238, // IOParam (for mounting and renaming), also used for temporary storage
|
|
fsVMI = 288, // VoumeMountInfoHeader (for mounting)
|
|
fsParseRec = 296, // ParsePathRec struct
|
|
fsReturn = 306, // Area for return data of 68k routines
|
|
fsAllocateVCB = 562, // UTAllocateVCB(uint16 *sysVCBLength{a0}, uint32 *vcb{a1})
|
|
fsAddNewVCB = 578, // UTAddNewVCB(int drive_number{d0}, int16 *vRefNum{a1}, uint32 vcb{a1})
|
|
fsDetermineVol = 594, // UTDetermineVol(uint32 pb{a0}, int16 *status{a1}, int16 *more_matches{a2}, int16 *vRefNum{a3}, uint32 *vcb{a4})
|
|
fsResolveWDCB = 614, // UTResolveWDCB(uint32 procID{d0}, int16 index{d1}, int16 vRefNum{d0}, uint32 *wdcb{a0})
|
|
fsGetDefaultVol = 632, // UTGetDefaultVol(uint32 wdpb{a0})
|
|
fsGetPathComponentName = 644, // UTGetPathComponentName(uint32 rec{a0})
|
|
fsParsePathname = 656, // UTParsePathname(uint32 *start{a0}, uint32 name{a1})
|
|
fsDisposeVCB = 670, // UTDisposeVCB(uint32 vcb{a0})
|
|
fsCheckWDRefNum = 682, // UTCheckWDRefNum(int16 refNum{d0})
|
|
fsSetDefaultVol = 694, // UTSetDefaultVol(uint32 dummy{d0}, int32 dirID{d1}, int16 refNum{d2})
|
|
fsAllocateFCB = 710, // UTAllocateFCB(int16 *refNum{a0}, uint32 *fcb{a1})
|
|
fsReleaseFCB = 724, // UTReleaseFCB(int16 refNum{d0})
|
|
fsIndexFCB = 736, // UTIndexFCB(uint32 vcb{a0}, int16 *refNum{a1}, uint32 *fcb{a2})
|
|
fsResolveFCB = 752, // UTResolveFCB(int16 refNum{d0}, uint32 *fcb{a0})
|
|
fsAdjustEOF = 766, // UTAdjustEOF(int16 refNum{d0})
|
|
fsAllocateWDCB = 778, // UTAllocateWDCB(uint32 pb{a0})
|
|
fsReleaseWDCB = 790, // UTReleaseWDCB(int16 vRefNum{d0})
|
|
SIZEOF_fsdat = 802
|
|
};
|
|
|
|
static uint32 fs_data = 0; // Mac address of global data
|
|
|
|
|
|
// File system and volume name
|
|
static char FS_NAME[32], VOLUME_NAME[32];
|
|
|
|
// This directory is our root (read from prefs)
|
|
static const char *RootPath;
|
|
static bool ready = false;
|
|
static struct stat root_stat;
|
|
|
|
// File system ID/media type
|
|
const int16 MY_FSID = EMULATOR_ID_2;
|
|
const uint32 MY_MEDIA_TYPE = EMULATOR_ID_4;
|
|
|
|
// CNID of root and root's parent
|
|
const uint32 ROOT_ID = 2;
|
|
const uint32 ROOT_PARENT_ID = 1;
|
|
|
|
// File system stack size
|
|
const int STACK_SIZE = 0x10000;
|
|
|
|
// Allocation block and clump size as reported to MacOS (these are of course
|
|
// not the real values and have no meaning on the host OS)
|
|
const int AL_BLK_SIZE = 0x4000;
|
|
const int CLUMP_SIZE = 0x4000;
|
|
|
|
// Drive number of our pseudo-drive
|
|
static int drive_number;
|
|
|
|
|
|
// Disk/drive icon
|
|
const uint8 ExtFSIcon[256] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe,
|
|
0x80, 0x00, 0x00, 0x91, 0x80, 0x00, 0x00, 0x91, 0x80, 0x00, 0x01, 0x21, 0x80, 0x00, 0x01, 0x21,
|
|
0x80, 0x00, 0x02, 0x41, 0x8c, 0x00, 0x02, 0x41, 0x80, 0x00, 0x04, 0x81, 0x80, 0x00, 0x04, 0x81,
|
|
0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
|
|
// These objects are used to map CNIDs to path names
|
|
struct FSItem {
|
|
FSItem *next; // Pointer to next FSItem in list
|
|
uint32 id; // CNID of this file/dir
|
|
uint32 parent_id; // CNID of parent file/dir
|
|
FSItem *parent; // Pointer to parent
|
|
char *name; // Object name (C string) - Host OS
|
|
char guest_name[32]; // Object name (C string) - Guest OS
|
|
time_t mtime; // Modification time for get_cat_info caching
|
|
int cache_dircount; // Cached number of files in directory
|
|
};
|
|
|
|
static FSItem *first_fs_item, *last_fs_item;
|
|
|
|
static uint32 next_cnid = fsUsrCNID; // Next available CNID
|
|
|
|
|
|
/*
|
|
* Get object creation time
|
|
*/
|
|
|
|
#if defined __APPLE__ && defined __MACH__
|
|
struct crtimebuf {
|
|
unsigned long length;
|
|
struct timespec crtime;
|
|
};
|
|
|
|
static uint32 do_get_creation_time(const char *path)
|
|
{
|
|
struct attrlist attr;
|
|
memset(&attr, 0, sizeof(attr));
|
|
attr.bitmapcount = ATTR_BIT_MAP_COUNT;
|
|
attr.commonattr = ATTR_CMN_CRTIME;
|
|
|
|
crtimebuf buf;
|
|
if (getattrlist(path, &attr, &buf, sizeof(buf), FSOPT_NOFOLLOW) < 0)
|
|
return 0;
|
|
return TimeToMacTime(buf.crtime.tv_sec);
|
|
}
|
|
|
|
static uint32 get_creation_time(const char *path)
|
|
{
|
|
if (path == NULL)
|
|
return 0;
|
|
if (path == RootPath) {
|
|
static uint32 root_crtime = UINT_MAX;
|
|
if (root_crtime == UINT_MAX)
|
|
root_crtime = do_get_creation_time(path);
|
|
return root_crtime;
|
|
}
|
|
return do_get_creation_time(path);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Find FSItem for given CNID
|
|
*/
|
|
|
|
static FSItem *find_fsitem_by_id(uint32 cnid)
|
|
{
|
|
FSItem *p = first_fs_item;
|
|
while (p) {
|
|
if (p->id == cnid)
|
|
return p;
|
|
p = p->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Create FSItem with the given parameters
|
|
*/
|
|
|
|
static FSItem *create_fsitem(const char *name, const char *guest_name, FSItem *parent)
|
|
{
|
|
FSItem *p = new FSItem;
|
|
last_fs_item->next = p;
|
|
p->next = NULL;
|
|
last_fs_item = p;
|
|
p->id = next_cnid++;
|
|
p->parent_id = parent->id;
|
|
p->parent = parent;
|
|
p->name = new char[strlen(name) + 1];
|
|
strcpy(p->name, name);
|
|
strncpy(p->guest_name, guest_name, 31);
|
|
p->guest_name[31] = 0;
|
|
p->mtime = 0;
|
|
return p;
|
|
}
|
|
|
|
/*
|
|
* Find FSItem for given name and parent, construct new FSItem if not found
|
|
*/
|
|
|
|
static FSItem *find_fsitem(const char *name, FSItem *parent)
|
|
{
|
|
FSItem *p = first_fs_item;
|
|
while (p) {
|
|
if (p->parent == parent && !strcmp(p->name, name))
|
|
return p;
|
|
p = p->next;
|
|
}
|
|
|
|
// Not found, construct new FSItem
|
|
return create_fsitem(name, host_encoding_to_macroman(name), parent);
|
|
}
|
|
|
|
/*
|
|
* Find FSItem for given guest_name and parent, construct new FSItem if not found
|
|
*/
|
|
|
|
static FSItem *find_fsitem_guest(const char *guest_name, FSItem *parent)
|
|
{
|
|
FSItem *p = first_fs_item;
|
|
while (p) {
|
|
if (p->parent == parent && !strcmp(p->guest_name, guest_name))
|
|
return p;
|
|
p = p->next;
|
|
}
|
|
|
|
// Not found, construct new FSItem
|
|
return create_fsitem(macroman_to_host_encoding(guest_name), guest_name, parent);
|
|
}
|
|
|
|
/*
|
|
* Get full path (->full_path) for given FSItem
|
|
*/
|
|
|
|
static char full_path[MAX_PATH_LENGTH];
|
|
|
|
static void add_path_comp(const char *s)
|
|
{
|
|
add_path_component(full_path, s);
|
|
}
|
|
|
|
static void get_path_for_fsitem(FSItem *p)
|
|
{
|
|
if (p->id == ROOT_PARENT_ID) {
|
|
full_path[0] = 0;
|
|
} else if (p->id == ROOT_ID) {
|
|
strncpy(full_path, RootPath, MAX_PATH_LENGTH-1);
|
|
full_path[MAX_PATH_LENGTH-1] = 0;
|
|
} else {
|
|
get_path_for_fsitem(p->parent);
|
|
add_path_comp(p->name);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Exchange parent CNIDs in all FSItems
|
|
*/
|
|
|
|
static void swap_parent_ids(uint32 parent1, uint32 parent2)
|
|
{
|
|
FSItem *p = first_fs_item;
|
|
while (p) {
|
|
if (p->parent_id == parent1)
|
|
p->parent_id = parent2;
|
|
else if (p->parent_id == parent2)
|
|
p->parent_id = parent1;
|
|
p = p->next;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* String handling functions
|
|
*/
|
|
|
|
// Copy pascal string
|
|
static void pstrcpy(char *dst, const char *src)
|
|
{
|
|
int size = *dst++ = *src++;
|
|
while (size--)
|
|
*dst++ = *src++;
|
|
}
|
|
|
|
// Convert C string to pascal string
|
|
static void cstr2pstr(char *dst, const char *src)
|
|
{
|
|
*dst++ = char(strlen(src));
|
|
char c;
|
|
while ((c = *src++) != 0) {
|
|
// Note: we are converting host ':' characters to Mac '/' characters here
|
|
// '/' is not a path separator as this function is only used on object names
|
|
if (c == ':')
|
|
c = '/';
|
|
*dst++ = c;
|
|
}
|
|
}
|
|
|
|
// Convert string (no length byte) to C string, length given separately
|
|
static void strn2cstr(char *dst, const char *src, int size)
|
|
{
|
|
while (size--) {
|
|
char c = *src++;
|
|
// Note: we are converting Mac '/' characters to host ':' characters here
|
|
// '/' is not a path separator as this function is only used on object names
|
|
if (c == '/')
|
|
c = ':';
|
|
*dst++ = c;
|
|
}
|
|
*dst = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Convert errno to MacOS error code
|
|
*/
|
|
|
|
static int16 errno2oserr(void)
|
|
{
|
|
D(bug(" errno %08x\n", errno));
|
|
switch (errno) {
|
|
case 0:
|
|
return noErr;
|
|
case ENOENT:
|
|
case EISDIR:
|
|
return fnfErr;
|
|
case EACCES:
|
|
case EPERM:
|
|
return permErr;
|
|
case EEXIST:
|
|
return dupFNErr;
|
|
case EBUSY:
|
|
case ENOTEMPTY:
|
|
return fBsyErr;
|
|
case ENOSPC:
|
|
return dskFulErr;
|
|
case EROFS:
|
|
return wPrErr;
|
|
case EMFILE:
|
|
return tmfoErr;
|
|
case ENOMEM:
|
|
return -108;
|
|
case EIO:
|
|
default:
|
|
return ioErr;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Initialization
|
|
*/
|
|
|
|
void ExtFSInit(void)
|
|
{
|
|
// System specific initialization
|
|
extfs_init();
|
|
|
|
// Get file system and volume name
|
|
cstr2pstr(FS_NAME, GetString(STR_EXTFS_NAME));
|
|
cstr2pstr(VOLUME_NAME, GetString(STR_EXTFS_VOLUME_NAME));
|
|
|
|
// Create root's parent FSItem
|
|
FSItem *p = new FSItem;
|
|
first_fs_item = last_fs_item = p;
|
|
p->next = NULL;
|
|
p->id = ROOT_PARENT_ID;
|
|
p->parent_id = 0;
|
|
p->parent = NULL;
|
|
p->name = new char[1];
|
|
p->name[0] = 0;
|
|
p->guest_name[0] = 0;
|
|
|
|
// Create root FSItem
|
|
p = new FSItem;
|
|
last_fs_item->next = p;
|
|
p->next = NULL;
|
|
last_fs_item = p;
|
|
p->id = ROOT_ID;
|
|
p->parent_id = ROOT_PARENT_ID;
|
|
p->parent = first_fs_item;
|
|
const char *volume_name = GetString(STR_EXTFS_VOLUME_NAME);
|
|
p->name = new char[strlen(volume_name) + 1];
|
|
strcpy(p->name, volume_name);
|
|
strncpy(p->guest_name, host_encoding_to_macroman(p->name), 32);
|
|
p->guest_name[31] = 0;
|
|
|
|
// Find path for root
|
|
if ((RootPath = PrefsFindString("extfs")) != NULL) {
|
|
if (stat(RootPath, &root_stat))
|
|
return;
|
|
if (!S_ISDIR(root_stat.st_mode))
|
|
return;
|
|
ready = true;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Deinitialization
|
|
*/
|
|
|
|
void ExtFSExit(void)
|
|
{
|
|
// Delete all FSItems
|
|
FSItem *p = first_fs_item, *next;
|
|
while (p) {
|
|
next = p->next;
|
|
delete[] p->name;
|
|
delete p;
|
|
p = next;
|
|
}
|
|
first_fs_item = last_fs_item = NULL;
|
|
|
|
// System specific deinitialization
|
|
extfs_exit();
|
|
}
|
|
|
|
|
|
/*
|
|
* Install file system
|
|
*/
|
|
|
|
void InstallExtFS(void)
|
|
{
|
|
int num_blocks = 0xffff; // Fake number of blocks of our drive
|
|
M68kRegisters r;
|
|
|
|
D(bug("InstallExtFS\n"));
|
|
if (!ready)
|
|
return;
|
|
|
|
// FSM present?
|
|
r.d[0] = gestaltFSAttr;
|
|
Execute68kTrap(0xa1ad, &r); // Gestalt()
|
|
D(bug("FSAttr %d, %08x\n", r.d[0], r.a[0]));
|
|
if ((r.d[0] & 0xffff) || !(r.a[0] & (1 << gestaltHasFileSystemManager))) {
|
|
printf("WARNING: No FSM present, disabling ExtFS\n");
|
|
return;
|
|
}
|
|
|
|
// Yes, version >=1.2?
|
|
r.d[0] = gestaltFSMVersion;
|
|
Execute68kTrap(0xa1ad, &r); // Gestalt()
|
|
D(bug("FSMVersion %d, %08x\n", r.d[0], r.a[0]));
|
|
if ((r.d[0] & 0xffff) || (r.a[0] < 0x0120)) {
|
|
printf("WARNING: FSM <1.2 found, disabling ExtFS\n");
|
|
return;
|
|
}
|
|
|
|
D(bug("FSM present\n"));
|
|
|
|
// Yes, allocate file system stack
|
|
r.d[0] = STACK_SIZE;
|
|
Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
|
|
if (r.a[0] == 0)
|
|
return;
|
|
uint32 fs_stack = r.a[0];
|
|
|
|
// Allocate memory for our data structures and 68k code
|
|
r.d[0] = SIZEOF_fsdat;
|
|
Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
|
|
if (r.a[0] == 0)
|
|
return;
|
|
fs_data = r.a[0];
|
|
|
|
// Set up 68k code fragments
|
|
int p = fs_data + fsCommProcStub;
|
|
WriteMacInt16(p, M68K_EMUL_OP_EXTFS_COMM); p += 2;
|
|
WriteMacInt16(p, M68K_RTD); p += 2;
|
|
WriteMacInt16(p, 10); p += 2;
|
|
if (p - fs_data != fsHFSProcStub)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, M68K_EMUL_OP_EXTFS_HFS); p += 2;
|
|
WriteMacInt16(p, M68K_RTD); p += 2;
|
|
WriteMacInt16(p, 16);
|
|
p = fs_data + fsAllocateVCB;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp)
|
|
WriteMacInt16(p, 0x2f09); p+= 2; // move.l a1,-(sp)
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x7006); p+= 2; // UTAllocateVCB
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsAddNewVCB)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x3f00); p+= 2; // move.w d0,-(sp)
|
|
WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(a7)
|
|
WriteMacInt16(p, 0x2f09); p+= 2; // move.l a1,-(a7)
|
|
WriteMacInt16(p, 0x7007); p+= 2; // UTAddNewVCB
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsDetermineVol)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp)
|
|
WriteMacInt16(p, 0x2f09); p+= 2; // move.l a1,-(sp)
|
|
WriteMacInt16(p, 0x2f0a); p+= 2; // move.l a2,-(sp)
|
|
WriteMacInt16(p, 0x2f0b); p+= 2; // move.l a3,-(sp)
|
|
WriteMacInt16(p, 0x2f0c); p+= 2; // move.l a4,-(sp)
|
|
WriteMacInt16(p, 0x701d); p+= 2; // UTDetermineVol
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsResolveWDCB)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x2f00); p+= 2; // move.l d0,-(sp)
|
|
WriteMacInt16(p, 0x3f01); p+= 2; // move.w d1,-(sp)
|
|
WriteMacInt16(p, 0x3f02); p+= 2; // move.w d2,-(sp)
|
|
WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp)
|
|
WriteMacInt16(p, 0x700e); p+= 2; // UTResolveWDCB
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsGetDefaultVol)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp)
|
|
WriteMacInt16(p, 0x7012); p+= 2; // UTGetDefaultVol
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsGetPathComponentName)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp)
|
|
WriteMacInt16(p, 0x701c); p+= 2; // UTGetPathComponentName
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsParsePathname)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp)
|
|
WriteMacInt16(p, 0x2f09); p+= 2; // move.l a1,-(sp)
|
|
WriteMacInt16(p, 0x701b); p+= 2; // UTParsePathname
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsDisposeVCB)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp)
|
|
WriteMacInt16(p, 0x7008); p+= 2; // UTDisposeVCB
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsCheckWDRefNum)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x3f00); p+= 2; // move.w d0,-(sp)
|
|
WriteMacInt16(p, 0x7013); p+= 2; // UTCheckWDRefNum
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsSetDefaultVol)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x2f00); p+= 2; // move.l d0,-(sp)
|
|
WriteMacInt16(p, 0x2f01); p+= 2; // move.l d1,-(sp)
|
|
WriteMacInt16(p, 0x3f02); p+= 2; // move.w d2,-(sp)
|
|
WriteMacInt16(p, 0x7011); p+= 2; // UTSetDefaultVol
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsAllocateFCB)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp)
|
|
WriteMacInt16(p, 0x2f09); p+= 2; // move.l a1,-(sp)
|
|
WriteMacInt16(p, 0x7000); p+= 2; // UTAllocateFCB
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsReleaseFCB)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x3f00); p+= 2; // move.w d0,-(sp)
|
|
WriteMacInt16(p, 0x7001); p+= 2; // UTReleaseFCB
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsIndexFCB)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp)
|
|
WriteMacInt16(p, 0x2f09); p+= 2; // move.l a1,-(sp)
|
|
WriteMacInt16(p, 0x2f0a); p+= 2; // move.l a2,-(sp)
|
|
WriteMacInt16(p, 0x7004); p+= 2; // UTIndexFCB
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsResolveFCB)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x3f00); p+= 2; // move.w d0,-(sp)
|
|
WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp)
|
|
WriteMacInt16(p, 0x7005); p+= 2; // UTResolveFCB
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsAdjustEOF)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x3f00); p+= 2; // move.w d0,-(sp)
|
|
WriteMacInt16(p, 0x7010); p+= 2; // UTAdjustEOF
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsAllocateWDCB)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x2f08); p+= 2; // move.l a0,-(sp)
|
|
WriteMacInt16(p, 0x700c); p+= 2; // UTAllocateWDCB
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != fsReleaseWDCB)
|
|
goto fsdat_error;
|
|
WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp)
|
|
WriteMacInt16(p, 0x3f00); p+= 2; // move.w d0,-(sp)
|
|
WriteMacInt16(p, 0x700d); p+= 2; // UTReleaseWDCB
|
|
WriteMacInt16(p, 0xa824); p+= 2; // FSMgr
|
|
WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0
|
|
WriteMacInt16(p, M68K_RTS); p+= 2;
|
|
if (p - fs_data != SIZEOF_fsdat)
|
|
goto fsdat_error;
|
|
|
|
// Set up drive status
|
|
WriteMacInt8(fs_data + fsDrvStatus + dsDiskInPlace, 8); // Fixed disk
|
|
WriteMacInt8(fs_data + fsDrvStatus + dsInstalled, 1);
|
|
WriteMacInt16(fs_data + fsDrvStatus + dsQType, hard20);
|
|
WriteMacInt16(fs_data + fsDrvStatus + dsDriveSize, num_blocks & 0xffff);
|
|
WriteMacInt16(fs_data + fsDrvStatus + dsDriveS1, num_blocks >> 16);
|
|
WriteMacInt16(fs_data + fsDrvStatus + dsQFSID, MY_FSID);
|
|
|
|
// Add drive to drive queue
|
|
drive_number = FindFreeDriveNumber(1);
|
|
D(bug(" adding drive %d\n", drive_number));
|
|
r.d[0] = (drive_number << 16) | (DiskRefNum & 0xffff);
|
|
r.a[0] = fs_data + fsDrvStatus + dsQLink;
|
|
Execute68kTrap(0xa04e, &r); // AddDrive()
|
|
|
|
// Init FSDRec and install file system
|
|
D(bug(" installing file system\n"));
|
|
WriteMacInt16(fs_data + fsFSD + fsdLength, SIZEOF_FSDRec);
|
|
WriteMacInt16(fs_data + fsFSD + fsdVersion, fsdVersion1);
|
|
WriteMacInt16(fs_data + fsFSD + fileSystemFSID, MY_FSID);
|
|
Host2Mac_memcpy(fs_data + fsFSD + fileSystemName, FS_NAME, 32);
|
|
WriteMacInt32(fs_data + fsFSD + fileSystemCommProc, fs_data + fsCommProcStub);
|
|
WriteMacInt32(fs_data + fsFSD + fsdHFSCI + compInterfProc, fs_data + fsHFSProcStub);
|
|
WriteMacInt32(fs_data + fsFSD + fsdHFSCI + stackTop, fs_stack + STACK_SIZE);
|
|
WriteMacInt32(fs_data + fsFSD + fsdHFSCI + stackSize, STACK_SIZE);
|
|
WriteMacInt32(fs_data + fsFSD + fsdHFSCI + idSector, (uint32)-1);
|
|
r.a[0] = fs_data + fsFSD;
|
|
r.d[0] = 0; // InstallFS
|
|
Execute68kTrap(0xa0ac, &r); // FSMDispatch()
|
|
D(bug(" InstallFS() returned %d\n", r.d[0]));
|
|
|
|
// Enable HFS component
|
|
D(bug(" enabling HFS component\n"));
|
|
WriteMacInt32(fs_data + fsFSD + fsdHFSCI + compInterfMask, ReadMacInt32(fs_data + fsFSD + fsdHFSCI + compInterfMask) | (fsmComponentEnableMask | hfsCIResourceLoadedMask | hfsCIDoesHFSMask));
|
|
r.a[0] = fs_data + fsFSD;
|
|
r.d[3] = SIZEOF_FSDRec;
|
|
r.d[4] = MY_FSID;
|
|
r.d[0] = 5; // SetFSInfo
|
|
Execute68kTrap(0xa0ac, &r); // FSMDispatch()
|
|
D(bug(" SetFSInfo() returned %d\n", r.d[0]));
|
|
|
|
// Mount volume
|
|
D(bug(" mounting volume\n"));
|
|
WriteMacInt32(fs_data + fsPB + ioBuffer, fs_data + fsVMI);
|
|
WriteMacInt16(fs_data + fsVMI + vmiLength, SIZEOF_VolumeMountInfoHeader);
|
|
WriteMacInt32(fs_data + fsVMI + vmiMedia, MY_MEDIA_TYPE);
|
|
r.a[0] = fs_data + fsPB;
|
|
r.d[0] = 0x41; // PBVolumeMount
|
|
Execute68kTrap(0xa260, &r); // HFSDispatch()
|
|
D(bug(" PBVolumeMount() returned %d\n", r.d[0]));
|
|
return;
|
|
|
|
fsdat_error:
|
|
printf("FATAL: ExtFS data block initialization error\n");
|
|
QuitEmulator();
|
|
}
|
|
|
|
|
|
/*
|
|
* FS communications function
|
|
*/
|
|
|
|
int16 ExtFSComm(uint16 message, uint32 paramBlock, uint32 globalsPtr)
|
|
{
|
|
D(bug("ExtFSComm(%d, %08lx, %08lx)\n", message, paramBlock, globalsPtr));
|
|
|
|
switch (message) {
|
|
case ffsNopMessage:
|
|
case ffsLoadMessage:
|
|
case ffsUnloadMessage:
|
|
return noErr;
|
|
|
|
case ffsGetIconMessage: { // Get disk/drive icon
|
|
if (ReadMacInt8(paramBlock + iconType) == kLargeIcon && ReadMacInt32(paramBlock + requestSize) >= sizeof(ExtFSIcon)) {
|
|
Host2Mac_memcpy(ReadMacInt32(paramBlock + iconBufferPtr), ExtFSIcon, sizeof(ExtFSIcon));
|
|
WriteMacInt32(paramBlock + actualSize, sizeof(ExtFSIcon));
|
|
return noErr;
|
|
} else
|
|
return -5012; // afpItemNotFound
|
|
}
|
|
|
|
case ffsIDDiskMessage: { // Check if volume is handled by our FS
|
|
if ((int16)ReadMacInt16(paramBlock + ioVRefNum) == drive_number)
|
|
return noErr;
|
|
else
|
|
return extFSErr;
|
|
}
|
|
|
|
case ffsIDVolMountMessage: { // Check if volume can be mounted by our FS
|
|
if (ReadMacInt32(ReadMacInt32(paramBlock + ioBuffer) + vmiMedia) == MY_MEDIA_TYPE)
|
|
return noErr;
|
|
else
|
|
return extFSErr;
|
|
}
|
|
|
|
default:
|
|
return fsmUnknownFSMMessageErr;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Get current directory specified by given ParamBlock/dirID
|
|
*/
|
|
|
|
static int16 get_current_dir(uint32 pb, uint32 dirID, uint32 ¤t_dir, bool no_vol_name = false)
|
|
{
|
|
M68kRegisters r;
|
|
int16 result;
|
|
|
|
// Determine volume
|
|
D(bug(" determining volume, dirID %d\n", dirID));
|
|
r.a[0] = pb;
|
|
r.a[1] = fs_data + fsReturn;
|
|
r.a[2] = fs_data + fsReturn + 2;
|
|
r.a[3] = fs_data + fsReturn + 4;
|
|
r.a[4] = fs_data + fsReturn + 6;
|
|
uint32 name_ptr = 0;
|
|
if (no_vol_name) {
|
|
name_ptr = ReadMacInt32(pb + ioNamePtr);
|
|
WriteMacInt32(pb + ioNamePtr, 0);
|
|
}
|
|
Execute68k(fs_data + fsDetermineVol, &r);
|
|
if (no_vol_name)
|
|
WriteMacInt32(pb + ioNamePtr, name_ptr);
|
|
int16 status = ReadMacInt16(fs_data + fsReturn);
|
|
D(bug(" UTDetermineVol() returned %d, status %d\n", r.d[0], status));
|
|
result = (int16)(r.d[0] & 0xffff);
|
|
|
|
if (result == noErr) {
|
|
switch (status) {
|
|
case dtmvFullPathname: // Determined by full pathname
|
|
current_dir = ROOT_ID;
|
|
break;
|
|
|
|
case dtmvVRefNum: // Determined by refNum or by drive number
|
|
case dtmvDriveNum:
|
|
current_dir = dirID ? dirID : ROOT_ID;
|
|
break;
|
|
|
|
case dtmvWDRefNum: // Determined by working directory refNum
|
|
if (dirID) {
|
|
current_dir = dirID;
|
|
} else {
|
|
D(bug(" resolving WDCB\n"));
|
|
r.d[0] = 0;
|
|
r.d[1] = 0;
|
|
r.d[2] = ReadMacInt16(pb + ioVRefNum);
|
|
r.a[0] = fs_data + fsReturn;
|
|
Execute68k(fs_data + fsResolveWDCB, &r);
|
|
uint32 wdcb = ReadMacInt32(fs_data + fsReturn);
|
|
D(bug(" UTResolveWDCB() returned %d, dirID %d\n", r.d[0], ReadMacInt32(wdcb + wdDirID)));
|
|
result = (int16)(r.d[0] & 0xffff);
|
|
if (result == noErr)
|
|
current_dir = ReadMacInt32(wdcb + wdDirID);
|
|
}
|
|
break;
|
|
|
|
case dtmvDefault: // Determined by default volume
|
|
if (dirID) {
|
|
current_dir = dirID;
|
|
} else {
|
|
uint32 wdpb = fs_data + fsReturn;
|
|
WriteMacInt32(wdpb + ioNamePtr, 0);
|
|
D(bug(" getting default volume\n"));
|
|
r.a[0] = wdpb;
|
|
Execute68k(fs_data + fsGetDefaultVol, &r);
|
|
D(bug(" UTGetDefaultVol() returned %d, dirID %d\n", r.d[0], ReadMacInt32(wdpb + ioWDDirID)));
|
|
result = (int16)(r.d[0] & 0xffff);
|
|
if (result == noErr)
|
|
current_dir = ReadMacInt32(wdpb + ioWDDirID);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
result = paramErr;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
/*
|
|
* Get path component name
|
|
*/
|
|
|
|
static int16 get_path_component_name(uint32 rec)
|
|
{
|
|
// D(bug(" getting path component\n"));
|
|
M68kRegisters r;
|
|
r.a[0] = rec;
|
|
Execute68k(fs_data + fsGetPathComponentName, &r);
|
|
// D(bug(" UTGetPathComponentName returned %d\n", r.d[0]));
|
|
return (int16)(r.d[0] & 0xffff);
|
|
}
|
|
|
|
|
|
/*
|
|
* Get FSItem and full path (->full_path) for file/dir specified in ParamBlock
|
|
*/
|
|
|
|
static int16 get_item_and_path(uint32 pb, uint32 dirID, FSItem *&item, bool no_vol_name = false)
|
|
{
|
|
M68kRegisters r;
|
|
|
|
// Find FSItem for parent directory
|
|
int16 result;
|
|
uint32 current_dir;
|
|
if ((result = get_current_dir(pb, dirID, current_dir, no_vol_name)) != noErr)
|
|
return result;
|
|
D(bug(" current dir %08x\n", current_dir));
|
|
FSItem *p = find_fsitem_by_id(current_dir);
|
|
if (p == NULL)
|
|
return dirNFErr;
|
|
|
|
// Start parsing
|
|
uint32 parseRec = fs_data + fsParseRec;
|
|
WriteMacInt32(parseRec + ppNamePtr, ReadMacInt32(pb + ioNamePtr));
|
|
WriteMacInt16(parseRec + ppStartOffset, 0);
|
|
WriteMacInt16(parseRec + ppComponentLength, 0);
|
|
WriteMacInt8(parseRec + ppMoreName, false);
|
|
WriteMacInt8(parseRec + ppFoundDelimiter, false);
|
|
|
|
// Get length of volume name
|
|
D(bug(" parsing pathname\n"));
|
|
r.a[0] = parseRec + ppStartOffset;
|
|
r.a[1] = ReadMacInt32(parseRec + ppNamePtr);
|
|
Execute68k(fs_data + fsParsePathname, &r);
|
|
D(bug(" UTParsePathname() returned %d, startOffset %d\n", r.d[0], ReadMacInt16(parseRec + ppStartOffset)));
|
|
result = (int16)(r.d[0] & 0xffff);
|
|
if (result == noErr) {
|
|
|
|
// Check for leading delimiter of the partial pathname
|
|
result = get_path_component_name(parseRec);
|
|
if (result == noErr) {
|
|
if (ReadMacInt16(parseRec + ppComponentLength) == 0 && ReadMacInt8(parseRec + ppFoundDelimiter)) {
|
|
// Get past initial delimiter
|
|
WriteMacInt16(parseRec + ppStartOffset, ReadMacInt16(parseRec + ppStartOffset) + 1);
|
|
}
|
|
|
|
// Parse until there is no more pathname to parse
|
|
while ((result == noErr) && ReadMacInt8(parseRec + ppMoreName)) {
|
|
|
|
// Search for the next delimiter from startOffset
|
|
result = get_path_component_name(parseRec);
|
|
if (result == noErr) {
|
|
if (ReadMacInt16(parseRec + ppComponentLength) == 0) {
|
|
|
|
// Delimiter immediately following another delimiter, get parent
|
|
if (current_dir != ROOT_ID) {
|
|
p = p->parent;
|
|
current_dir = p->id;
|
|
} else
|
|
result = bdNamErr;
|
|
|
|
// startOffset = start of next component
|
|
WriteMacInt16(parseRec + ppStartOffset, ReadMacInt16(parseRec + ppStartOffset) + 1);
|
|
|
|
} else if (ReadMacInt8(parseRec + ppMoreName)) {
|
|
|
|
// Component found and isn't the last, so it must be a directory, enter it
|
|
char name[32];
|
|
strn2cstr(name, (char *)Mac2HostAddr(ReadMacInt32(parseRec + ppNamePtr)) + ReadMacInt16(parseRec + ppStartOffset) + 1, ReadMacInt16(parseRec + ppComponentLength));
|
|
D(bug(" entering %s\n", name));
|
|
p = find_fsitem_guest(name, p);
|
|
current_dir = p->id;
|
|
|
|
// startOffset = start of next component
|
|
WriteMacInt16(parseRec + ppStartOffset, ReadMacInt16(parseRec + ppStartOffset) + ReadMacInt16(parseRec + ppComponentLength) + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result == noErr) {
|
|
|
|
// There is no more pathname to parse
|
|
if (ReadMacInt16(parseRec + ppComponentLength) == 0) {
|
|
|
|
// Pathname ended with '::' or was simply a volume name, so current directory is the object
|
|
item = p;
|
|
|
|
} else {
|
|
|
|
// Pathname ended with 'name:' or 'name', so name is the object
|
|
char name[32];
|
|
strn2cstr(name, (char *)Mac2HostAddr(ReadMacInt32(parseRec + ppNamePtr)) + ReadMacInt16(parseRec + ppStartOffset) + 1, ReadMacInt16(parseRec + ppComponentLength));
|
|
D(bug(" object is %s\n", name));
|
|
item = find_fsitem_guest(name, p);
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
// Default to bad name
|
|
result = bdNamErr;
|
|
|
|
if (ReadMacInt32(pb + ioNamePtr) == 0 || ReadMacInt8(ReadMacInt32(pb + ioNamePtr)) == 0) {
|
|
|
|
// Pathname was NULL or a zero length string, so we found a directory at the end of the string
|
|
item = p;
|
|
result = noErr;
|
|
}
|
|
}
|
|
|
|
// Eat the path
|
|
if (result == noErr) {
|
|
get_path_for_fsitem(item);
|
|
D(bug(" path %s\n", full_path));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
/*
|
|
* Find FCB for given file RefNum
|
|
*/
|
|
|
|
static uint32 find_fcb(int16 refNum)
|
|
{
|
|
D(bug(" finding FCB\n"));
|
|
M68kRegisters r;
|
|
r.d[0] = refNum;
|
|
r.a[0] = fs_data + fsReturn;
|
|
Execute68k(fs_data + fsResolveFCB, &r);
|
|
uint32 fcb = ReadMacInt32(fs_data + fsReturn);
|
|
D(bug(" UTResolveFCB() returned %d, fcb %08lx\n", r.d[0], fcb));
|
|
if (r.d[0] & 0xffff)
|
|
return 0;
|
|
else
|
|
return fcb;
|
|
}
|
|
|
|
|
|
/*
|
|
* HFS interface functions
|
|
*/
|
|
|
|
// Check if volume belongs to our FS
|
|
static int16 fs_mount_vol(uint32 pb)
|
|
{
|
|
D(bug(" fs_mount_vol(%08lx), vRefNum %d\n", pb, ReadMacInt16(pb + ioVRefNum)));
|
|
if ((int16)ReadMacInt16(pb + ioVRefNum) == drive_number)
|
|
return noErr;
|
|
else
|
|
return extFSErr;
|
|
}
|
|
|
|
// Mount volume
|
|
static int16 fs_volume_mount(uint32 pb)
|
|
{
|
|
D(bug(" fs_volume_mount(%08lx)\n", pb));
|
|
M68kRegisters r;
|
|
|
|
// Create new VCB
|
|
D(bug(" creating VCB\n"));
|
|
r.a[0] = fs_data + fsReturn;
|
|
r.a[1] = fs_data + fsReturn + 2;
|
|
Execute68k(fs_data + fsAllocateVCB, &r);
|
|
#if DEBUG
|
|
uint16 sysVCBLength = ReadMacInt16(fs_data + fsReturn);
|
|
#endif
|
|
uint32 vcb = ReadMacInt32(fs_data + fsReturn + 2);
|
|
D(bug(" UTAllocateVCB() returned %d, vcb %08lx, size %d\n", r.d[0], vcb, sysVCBLength));
|
|
if (r.d[0] & 0xffff)
|
|
return (int16)r.d[0];
|
|
|
|
// Init VCB
|
|
WriteMacInt16(vcb + vcbSigWord, 0x4244);
|
|
#if defined(__BEOS__) || defined(WIN32)
|
|
WriteMacInt32(vcb + vcbCrDate, TimeToMacTime(root_stat.st_crtime));
|
|
#elif defined __APPLE__ && defined __MACH__
|
|
WriteMacInt32(vcb + vcbCrDate, get_creation_time(RootPath));
|
|
#else
|
|
WriteMacInt32(vcb + vcbCrDate, 0);
|
|
#endif
|
|
WriteMacInt32(vcb + vcbLsMod, TimeToMacTime(root_stat.st_mtime));
|
|
WriteMacInt32(vcb + vcbVolBkUp, 0);
|
|
WriteMacInt16(vcb + vcbNmFls, 1); //!!
|
|
WriteMacInt16(vcb + vcbNmRtDirs, 1); //!!
|
|
WriteMacInt16(vcb + vcbNmAlBlks, 0xffff); //!!
|
|
WriteMacInt32(vcb + vcbAlBlkSiz, AL_BLK_SIZE);
|
|
WriteMacInt32(vcb + vcbClpSiz, CLUMP_SIZE);
|
|
WriteMacInt32(vcb + vcbNxtCNID, next_cnid);
|
|
WriteMacInt16(vcb + vcbFreeBks, 0xffff); //!!
|
|
Host2Mac_memcpy(vcb + vcbVN, VOLUME_NAME, 28);
|
|
WriteMacInt16(vcb + vcbFSID, MY_FSID);
|
|
WriteMacInt32(vcb + vcbFilCnt, 1); //!!
|
|
WriteMacInt32(vcb + vcbDirCnt, 1); //!!
|
|
|
|
// Add VCB to VCB queue
|
|
D(bug(" adding VCB to queue\n"));
|
|
r.d[0] = drive_number;
|
|
r.a[0] = fs_data + fsReturn;
|
|
r.a[1] = vcb;
|
|
Execute68k(fs_data + fsAddNewVCB, &r);
|
|
int16 vRefNum = (int16)ReadMacInt32(fs_data + fsReturn);
|
|
D(bug(" UTAddNewVCB() returned %d, vRefNum %d\n", r.d[0], vRefNum));
|
|
if (r.d[0] & 0xffff)
|
|
return (int16)r.d[0];
|
|
|
|
// Post diskInsertEvent
|
|
D(bug(" posting diskInsertEvent\n"));
|
|
r.d[0] = drive_number;
|
|
r.a[0] = 7; // diskEvent
|
|
Execute68kTrap(0xa02f, &r); // PostEvent()
|
|
|
|
// Return volume RefNum
|
|
WriteMacInt16(pb + ioVRefNum, vRefNum);
|
|
return noErr;
|
|
}
|
|
|
|
// Unmount volume
|
|
static int16 fs_unmount_vol(uint32 vcb)
|
|
{
|
|
D(bug(" fs_unmount_vol(%08lx), vRefNum %d\n", vcb, ReadMacInt16(vcb + vcbVRefNum)));
|
|
M68kRegisters r;
|
|
|
|
// Remove and free VCB
|
|
D(bug(" freeing VCB\n"));
|
|
r.a[0] = vcb;
|
|
Execute68k(fs_data + fsDisposeVCB, &r);
|
|
D(bug(" UTDisposeVCB() returned %d\n", r.d[0]));
|
|
return (int16)r.d[0];
|
|
}
|
|
|
|
// Get information about a volume (HVolumeParam)
|
|
static int16 fs_get_vol_info(uint32 pb, bool hfs)
|
|
{
|
|
// D(bug(" fs_get_vol_info(%08lx)\n", pb));
|
|
|
|
// Fill in struct
|
|
if (ReadMacInt32(pb + ioNamePtr))
|
|
pstrcpy((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), VOLUME_NAME);
|
|
#if defined(__BEOS__) || defined(WIN32)
|
|
WriteMacInt32(pb + ioVCrDate, TimeToMacTime(root_stat.st_crtime));
|
|
#elif defined __APPLE__ && defined __MACH__
|
|
WriteMacInt32(pb + ioVCrDate, get_creation_time(RootPath));
|
|
#else
|
|
WriteMacInt32(pb + ioVCrDate, 0);
|
|
#endif
|
|
WriteMacInt32(pb + ioVLsMod, TimeToMacTime(root_stat.st_mtime));
|
|
WriteMacInt16(pb + ioVAtrb, 0);
|
|
WriteMacInt16(pb + ioVNmFls, 1); //!!
|
|
WriteMacInt16(pb + ioVBitMap, 0);
|
|
WriteMacInt16(pb + ioAllocPtr, 0);
|
|
WriteMacInt16(pb + ioVNmAlBlks, 0xffff); //!!
|
|
WriteMacInt32(pb + ioVAlBlkSiz, AL_BLK_SIZE);
|
|
WriteMacInt32(pb + ioVClpSiz, CLUMP_SIZE);
|
|
WriteMacInt16(pb + ioAlBlSt, 0);
|
|
WriteMacInt32(pb + ioVNxtCNID, next_cnid);
|
|
WriteMacInt16(pb + ioVFrBlk, 0xffff); //!!
|
|
if (hfs) {
|
|
WriteMacInt16(pb + ioVDrvInfo, drive_number);
|
|
WriteMacInt16(pb + ioVDRefNum, ReadMacInt16(fs_data + fsDrvStatus + dsQRefNum));
|
|
WriteMacInt16(pb + ioVFSID, MY_FSID);
|
|
WriteMacInt32(pb + ioVBkUp, 0);
|
|
WriteMacInt16(pb + ioVSeqNum, 0);
|
|
WriteMacInt32(pb + ioVWrCnt, 0);
|
|
WriteMacInt32(pb + ioVFilCnt, 1); //!!
|
|
WriteMacInt32(pb + ioVDirCnt, 1); //!!
|
|
Mac_memset(pb + ioVFndrInfo, 0, 32);
|
|
}
|
|
return noErr;
|
|
}
|
|
|
|
// Change volume information (HVolumeParam)
|
|
static int16 fs_set_vol_info(uint32 pb)
|
|
{
|
|
D(bug(" fs_set_vol_info(%08lx)\n", pb));
|
|
|
|
//!! times
|
|
return noErr;
|
|
}
|
|
|
|
// Get volume parameter block
|
|
static int16 fs_get_vol_parms(uint32 pb)
|
|
{
|
|
// D(bug(" fs_get_vol_parms(%08lx)\n", pb));
|
|
|
|
// Return parameter block
|
|
uint32 actual = ReadMacInt32(pb + ioReqCount);
|
|
if (actual > SIZEOF_GetVolParmsInfoBuffer)
|
|
actual = SIZEOF_GetVolParmsInfoBuffer;
|
|
WriteMacInt32(pb + ioActCount, actual);
|
|
uint32 p = ReadMacInt32(pb + ioBuffer);
|
|
if (actual > vMVersion) WriteMacInt16(p + vMVersion, 2);
|
|
if (actual > vMAttrib) WriteMacInt32(p + vMAttrib, kNoMiniFndr | kNoVNEdit | kNoLclSync | kTrshOffLine | kNoSwitchTo | kNoBootBlks | kNoSysDir | kHasExtFSVol);
|
|
if (actual > vMLocalHand) WriteMacInt32(p + vMLocalHand, 0);
|
|
if (actual > vMServerAdr) WriteMacInt32(p + vMServerAdr, 0);
|
|
if (actual > vMVolumeGrade) WriteMacInt32(p + vMVolumeGrade, 0);
|
|
if (actual > vMForeignPrivID) WriteMacInt16(p + vMForeignPrivID, 0);
|
|
return noErr;
|
|
}
|
|
|
|
// Get default volume (WDParam)
|
|
static int16 fs_get_vol(uint32 pb)
|
|
{
|
|
D(bug(" fs_get_vol(%08lx)\n", pb));
|
|
M68kRegisters r;
|
|
|
|
// Getting default volume
|
|
D(bug(" getting default volume\n"));
|
|
r.a[0] = pb;
|
|
Execute68k(fs_data + fsGetDefaultVol, &r);
|
|
D(bug(" UTGetDefaultVol() returned %d\n", r.d[0]));
|
|
return (int16)r.d[0];
|
|
}
|
|
|
|
// Set default volume (WDParam)
|
|
static int16 fs_set_vol(uint32 pb, bool hfs, uint32 vcb)
|
|
{
|
|
D(bug(" fs_set_vol(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt32(pb + ioWDDirID)));
|
|
M68kRegisters r;
|
|
|
|
// Determine parameters
|
|
uint32 dirID;
|
|
int16 refNum;
|
|
if (hfs) {
|
|
|
|
// Find FSItem for given dir
|
|
FSItem *fs_item;
|
|
int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioWDDirID), fs_item);
|
|
if (result != noErr)
|
|
return result;
|
|
|
|
// Is it a directory?
|
|
struct stat st;
|
|
if (stat(full_path, &st))
|
|
return dirNFErr;
|
|
if (!S_ISDIR(st.st_mode))
|
|
return dirNFErr;
|
|
|
|
// Get dirID and refNum
|
|
dirID = fs_item->id;
|
|
refNum = ReadMacInt16(vcb + vcbVRefNum);
|
|
|
|
} else {
|
|
|
|
// Is the given vRefNum a working directory number?
|
|
D(bug(" checking for WDRefNum\n"));
|
|
r.d[0] = ReadMacInt16(pb + ioVRefNum);
|
|
Execute68k(fs_data + fsCheckWDRefNum, &r);
|
|
D(bug(" UTCheckWDRefNum() returned %d\n", r.d[0]));
|
|
if (r.d[0] & 0xffff) {
|
|
// Volume refNum
|
|
dirID = ROOT_ID;
|
|
refNum = ReadMacInt16(vcb + vcbVRefNum);
|
|
} else {
|
|
// WD refNum
|
|
dirID = 0;
|
|
refNum = ReadMacInt16(pb + ioVRefNum);
|
|
}
|
|
}
|
|
|
|
// Setting default volume
|
|
D(bug(" setting default volume\n"));
|
|
r.d[0] = 0;
|
|
r.d[1] = dirID;
|
|
r.d[2] = refNum;
|
|
Execute68k(fs_data + fsSetDefaultVol, &r);
|
|
D(bug(" UTSetDefaultVol() returned %d\n", r.d[0]));
|
|
return (int16)r.d[0];
|
|
}
|
|
|
|
// Query file attributes (HFileParam)
|
|
static int16 fs_get_file_info(uint32 pb, bool hfs, uint32 dirID)
|
|
{
|
|
D(bug(" fs_get_file_info(%08lx), vRefNum %d, name %.31s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt16(pb + ioFDirIndex), dirID));
|
|
|
|
FSItem *fs_item;
|
|
int16 dir_index = ReadMacInt16(pb + ioFDirIndex);
|
|
if (dir_index <= 0) { // Query item specified by ioDirID and ioNamePtr
|
|
|
|
// Find FSItem for given file
|
|
int16 result = get_item_and_path(pb, dirID, fs_item);
|
|
if (result != noErr)
|
|
return result;
|
|
|
|
} else { // Query item in directory specified by ioDirID by index
|
|
|
|
// Find FSItem for parent directory
|
|
int16 result;
|
|
uint32 current_dir;
|
|
if ((result = get_current_dir(pb, dirID, current_dir, true)) != noErr)
|
|
return result;
|
|
FSItem *p = find_fsitem_by_id(current_dir);
|
|
if (p == NULL)
|
|
return dirNFErr;
|
|
get_path_for_fsitem(p);
|
|
|
|
// Look for nth item in directory and add name to path
|
|
DIR *d = opendir(full_path);
|
|
if (d == NULL)
|
|
return dirNFErr;
|
|
struct dirent *de = NULL;
|
|
for (int i=0; i<dir_index; i++) {
|
|
read_next_de:
|
|
de = readdir(d);
|
|
if (de == NULL) {
|
|
closedir(d);
|
|
return fnfErr;
|
|
}
|
|
if (de->d_name[0] == '.')
|
|
goto read_next_de; // Suppress names beginning with '.' (MacOS could interpret these as driver names)
|
|
//!! suppress directories
|
|
}
|
|
add_path_comp(de->d_name);
|
|
|
|
// Get FSItem for queried item
|
|
fs_item = find_fsitem(de->d_name, p);
|
|
closedir(d);
|
|
}
|
|
|
|
// Get stats
|
|
struct stat st;
|
|
if (stat(full_path, &st))
|
|
return fnfErr;
|
|
if (S_ISDIR(st.st_mode))
|
|
return fnfErr;
|
|
|
|
// Fill in struct from fs_item and stats
|
|
if (ReadMacInt32(pb + ioNamePtr))
|
|
cstr2pstr((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), fs_item->guest_name);
|
|
WriteMacInt16(pb + ioFRefNum, 0);
|
|
WriteMacInt8(pb + ioFlAttrib, access(full_path, W_OK) == 0 ? 0 : faLocked);
|
|
WriteMacInt32(pb + ioDirID, fs_item->id);
|
|
|
|
#if defined(__BEOS__) || defined(WIN32)
|
|
WriteMacInt32(pb + ioFlCrDat, TimeToMacTime(st.st_crtime));
|
|
#elif defined __APPLE__ && defined __MACH__
|
|
WriteMacInt32(pb + ioFlCrDat, get_creation_time(full_path));
|
|
#else
|
|
WriteMacInt32(pb + ioFlCrDat, 0);
|
|
#endif
|
|
WriteMacInt32(pb + ioFlMdDat, TimeToMacTime(st.st_mtime));
|
|
|
|
get_finfo(full_path, pb + ioFlFndrInfo, hfs ? pb + ioFlXFndrInfo : 0, false);
|
|
|
|
WriteMacInt16(pb + ioFlStBlk, 0);
|
|
WriteMacInt32(pb + ioFlLgLen, st.st_size);
|
|
WriteMacInt32(pb + ioFlPyLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1);
|
|
WriteMacInt16(pb + ioFlRStBlk, 0);
|
|
uint32 rf_size = get_rfork_size(full_path);
|
|
WriteMacInt32(pb + ioFlRLgLen, rf_size);
|
|
WriteMacInt32(pb + ioFlRPyLen, (rf_size | (AL_BLK_SIZE - 1)) + 1);
|
|
|
|
if (hfs) {
|
|
WriteMacInt32(pb + ioFlBkDat, 0);
|
|
WriteMacInt32(pb + ioFlParID, fs_item->parent_id);
|
|
WriteMacInt32(pb + ioFlClpSiz, 0);
|
|
}
|
|
return noErr;
|
|
}
|
|
|
|
// Set file attributes (HFileParam)
|
|
static int16 fs_set_file_info(uint32 pb, bool hfs, uint32 dirID)
|
|
{
|
|
D(bug(" fs_set_file_info(%08lx), vRefNum %d, name %.31s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt16(pb + ioFDirIndex), dirID));
|
|
|
|
// Find FSItem for given file/dir
|
|
FSItem *fs_item;
|
|
int16 result = get_item_and_path(pb, dirID, fs_item);
|
|
if (result != noErr)
|
|
return result;
|
|
|
|
// Get stats
|
|
struct stat st;
|
|
if (stat(full_path, &st) < 0)
|
|
return errno2oserr();
|
|
if (S_ISDIR(st.st_mode))
|
|
return fnfErr;
|
|
|
|
// Set Finder info
|
|
set_finfo(full_path, pb + ioFlFndrInfo, hfs ? pb + ioFlXFndrInfo : 0, false);
|
|
|
|
//!! times
|
|
return noErr;
|
|
}
|
|
|
|
// Query file/directory attributes
|
|
static int16 fs_get_cat_info(uint32 pb)
|
|
{
|
|
D(bug(" fs_get_cat_info(%08lx), vRefNum %d, name %.31s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt16(pb + ioFDirIndex), ReadMacInt32(pb + ioDirID)));
|
|
|
|
FSItem *fs_item;
|
|
int16 dir_index = ReadMacInt16(pb + ioFDirIndex);
|
|
if (dir_index < 0) { // Query directory specified by ioDirID
|
|
|
|
// Find FSItem for directory
|
|
fs_item = find_fsitem_by_id(ReadMacInt32(pb + ioDrDirID));
|
|
if (fs_item == NULL)
|
|
return dirNFErr;
|
|
get_path_for_fsitem(fs_item);
|
|
|
|
} else if (dir_index == 0) { // Query item specified by ioDirID and ioNamePtr
|
|
|
|
// Find FSItem for given file/dir
|
|
int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item);
|
|
if (result != noErr)
|
|
return result;
|
|
|
|
} else { // Query item in directory specified by ioDirID by index
|
|
|
|
// Find FSItem for parent directory
|
|
int16 result;
|
|
uint32 current_dir;
|
|
if ((result = get_current_dir(pb, ReadMacInt32(pb + ioDirID), current_dir, true)) != noErr)
|
|
return result;
|
|
FSItem *p = find_fsitem_by_id(current_dir);
|
|
if (p == NULL)
|
|
return dirNFErr;
|
|
get_path_for_fsitem(p);
|
|
|
|
// Look for nth item in directory and add name to path
|
|
DIR *d = opendir(full_path);
|
|
if (d == NULL)
|
|
return dirNFErr;
|
|
struct dirent *de = NULL;
|
|
for (int i=0; i<dir_index; i++) {
|
|
read_next_de:
|
|
de = readdir(d);
|
|
if (de == NULL) {
|
|
closedir(d);
|
|
return fnfErr;
|
|
}
|
|
if (de->d_name[0] == '.')
|
|
goto read_next_de; // Suppress names beginning with '.' (MacOS could interpret these as driver names)
|
|
}
|
|
add_path_comp(de->d_name);
|
|
|
|
// Get FSItem for queried item
|
|
fs_item = find_fsitem(de->d_name, p);
|
|
closedir(d);
|
|
}
|
|
D(bug(" path %s\n", full_path));
|
|
|
|
// Get stats
|
|
struct stat st;
|
|
if (stat(full_path, &st) < 0)
|
|
return errno2oserr();
|
|
if (dir_index == -1 && !S_ISDIR(st.st_mode))
|
|
return dirNFErr;
|
|
|
|
// Fill in struct from fs_item and stats
|
|
if (ReadMacInt32(pb + ioNamePtr))
|
|
cstr2pstr((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), fs_item->guest_name);
|
|
WriteMacInt16(pb + ioFRefNum, 0);
|
|
WriteMacInt8(pb + ioFlAttrib, (S_ISDIR(st.st_mode) ? faIsDir : 0) | (access(full_path, W_OK) == 0 ? 0 : faLocked));
|
|
WriteMacInt8(pb + ioACUser, 0);
|
|
WriteMacInt32(pb + ioDirID, fs_item->id);
|
|
WriteMacInt32(pb + ioFlParID, fs_item->parent_id);
|
|
#if defined(__BEOS__) || defined(WIN32)
|
|
WriteMacInt32(pb + ioFlCrDat, TimeToMacTime(st.st_crtime));
|
|
#elif defined __APPLE__ && defined __MACH__
|
|
WriteMacInt32(pb + ioFlCrDat, get_creation_time(full_path));
|
|
#else
|
|
WriteMacInt32(pb + ioFlCrDat, 0);
|
|
#endif
|
|
time_t mtime = st.st_mtime;
|
|
bool cached = true;
|
|
if (mtime > fs_item->mtime) {
|
|
fs_item->mtime = mtime;
|
|
cached = false;
|
|
}
|
|
WriteMacInt32(pb + ioFlMdDat, TimeToMacTime(mtime));
|
|
WriteMacInt32(pb + ioFlBkDat, 0);
|
|
|
|
get_finfo(full_path, pb + ioFlFndrInfo, pb + ioFlXFndrInfo, S_ISDIR(st.st_mode));
|
|
|
|
if (S_ISDIR(st.st_mode)) {
|
|
|
|
// Determine number of files in directory (cached)
|
|
int count;
|
|
if (cached)
|
|
count = fs_item->cache_dircount;
|
|
else {
|
|
count = 0;
|
|
DIR *d = opendir(full_path);
|
|
if (d) {
|
|
struct dirent *de;
|
|
for (;;) {
|
|
de = readdir(d);
|
|
if (de == NULL)
|
|
break;
|
|
if (de->d_name[0] == '.')
|
|
continue; // Suppress names beginning with '.'
|
|
count++;
|
|
}
|
|
closedir(d);
|
|
}
|
|
fs_item->cache_dircount = count;
|
|
}
|
|
WriteMacInt16(pb + ioDrNmFls, count);
|
|
} else {
|
|
WriteMacInt16(pb + ioFlStBlk, 0);
|
|
WriteMacInt32(pb + ioFlLgLen, st.st_size);
|
|
WriteMacInt32(pb + ioFlPyLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1);
|
|
WriteMacInt16(pb + ioFlRStBlk, 0);
|
|
uint32 rf_size = get_rfork_size(full_path);
|
|
WriteMacInt32(pb + ioFlRLgLen, rf_size);
|
|
WriteMacInt32(pb + ioFlRPyLen, (rf_size | (AL_BLK_SIZE - 1)) + 1);
|
|
WriteMacInt32(pb + ioFlClpSiz, 0);
|
|
}
|
|
return noErr;
|
|
}
|
|
|
|
// Set file/directory attributes
|
|
static int16 fs_set_cat_info(uint32 pb)
|
|
{
|
|
D(bug(" fs_set_cat_info(%08lx), vRefNum %d, name %.31s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt16(pb + ioFDirIndex), ReadMacInt32(pb + ioDirID)));
|
|
|
|
// Find FSItem for given file/dir
|
|
FSItem *fs_item;
|
|
int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item);
|
|
if (result != noErr)
|
|
return result;
|
|
|
|
// Get stats
|
|
struct stat st;
|
|
if (stat(full_path, &st) < 0)
|
|
return errno2oserr();
|
|
|
|
// Set Finder info
|
|
set_finfo(full_path, pb + ioFlFndrInfo, pb + ioFlXFndrInfo, S_ISDIR(st.st_mode));
|
|
|
|
//!! times
|
|
return noErr;
|
|
}
|
|
|
|
// Open file
|
|
static int16 fs_open(uint32 pb, uint32 dirID, uint32 vcb, bool resource_fork)
|
|
{
|
|
D(bug(" fs_open(%08lx), %s, vRefNum %d, name %.31s, dirID %d, perm %d\n", pb, resource_fork ? "rsrc" : "data", ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID, ReadMacInt8(pb + ioPermssn)));
|
|
M68kRegisters r;
|
|
|
|
// Find FSItem for given file
|
|
FSItem *fs_item;
|
|
int16 result = get_item_and_path(pb, dirID, fs_item);
|
|
if (result != noErr)
|
|
return result;
|
|
|
|
// Convert ioPermssn to open() flag
|
|
int flag = 0;
|
|
bool write_ok = (access(full_path, W_OK) == 0);
|
|
switch (ReadMacInt8(pb + ioPermssn)) {
|
|
case fsCurPerm: // Whatever is currently allowed
|
|
if (write_ok)
|
|
flag = O_RDWR;
|
|
else
|
|
flag = O_RDONLY;
|
|
break;
|
|
case fsRdPerm: // Exclusive read
|
|
flag = O_RDONLY;
|
|
break;
|
|
case fsWrPerm: // Exclusive write
|
|
flag = O_WRONLY;
|
|
break;
|
|
case fsRdWrPerm: // Exclusive read/write
|
|
case fsRdWrShPerm: // Shared read/write
|
|
default:
|
|
flag = O_RDWR;
|
|
break;
|
|
}
|
|
|
|
// Try to open and stat the file
|
|
int fd = -1;
|
|
struct stat st;
|
|
if (resource_fork) {
|
|
if (access(full_path, F_OK))
|
|
return fnfErr;
|
|
fd = open_rfork(full_path, flag);
|
|
if (fd >= 0) {
|
|
if (fstat(fd, &st) < 0) {
|
|
close(fd);
|
|
return errno2oserr();
|
|
}
|
|
} else { // Resource fork not supported, silently ignore it ("pseudo" resource fork)
|
|
st.st_size = 0;
|
|
st.st_mode = 0;
|
|
}
|
|
} else {
|
|
fd = open(full_path, flag);
|
|
if (fd < 0)
|
|
return errno2oserr();
|
|
if (fstat(fd, &st) < 0) {
|
|
close(fd);
|
|
return errno2oserr();
|
|
}
|
|
}
|
|
|
|
// File open, allocate FCB
|
|
D(bug(" allocating FCB\n"));
|
|
r.a[0] = pb + ioRefNum;
|
|
r.a[1] = fs_data + fsReturn;
|
|
Execute68k(fs_data + fsAllocateFCB, &r);
|
|
uint32 fcb = ReadMacInt32(fs_data + fsReturn);
|
|
D(bug(" UTAllocateFCB() returned %d, fRefNum %d, fcb %08lx\n", r.d[0], ReadMacInt16(pb + ioRefNum), fcb));
|
|
if (r.d[0] & 0xffff) {
|
|
close(fd);
|
|
return (int16)r.d[0];
|
|
}
|
|
|
|
// Initialize FCB, fd is stored in fcbCatPos
|
|
WriteMacInt32(fcb + fcbFlNm, fs_item->id);
|
|
WriteMacInt8(fcb + fcbFlags, ((flag == O_WRONLY || flag == O_RDWR) ? fcbWriteMask : 0) | (resource_fork ? fcbResourceMask : 0) | (write_ok ? 0 : fcbFileLockedMask));
|
|
WriteMacInt32(fcb + fcbEOF, st.st_size);
|
|
WriteMacInt32(fcb + fcbPLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1);
|
|
WriteMacInt32(fcb + fcbCrPs, 0);
|
|
WriteMacInt32(fcb + fcbVPtr, vcb);
|
|
WriteMacInt32(fcb + fcbClmpSize, CLUMP_SIZE);
|
|
|
|
get_finfo(full_path, fs_data + fsPB, 0, false);
|
|
WriteMacInt32(fcb + fcbFType, ReadMacInt32(fs_data + fsPB + fdType));
|
|
|
|
WriteMacInt32(fcb + fcbCatPos, fd);
|
|
WriteMacInt32(fcb + fcbDirID, fs_item->parent_id);
|
|
cstr2pstr((char *)Mac2HostAddr(fcb + fcbCName), fs_item->guest_name);
|
|
return noErr;
|
|
}
|
|
|
|
// Close file
|
|
static int16 fs_close(uint32 pb)
|
|
{
|
|
D(bug(" fs_close(%08lx), refNum %d\n", pb, ReadMacInt16(pb + ioRefNum)));
|
|
M68kRegisters r;
|
|
|
|
// Find FCB and fd for file
|
|
uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
|
|
if (fcb == 0)
|
|
return rfNumErr;
|
|
if (ReadMacInt32(fcb + fcbFlNm) == 0)
|
|
return fnOpnErr;
|
|
int fd = ReadMacInt32(fcb + fcbCatPos);
|
|
|
|
// Close file
|
|
if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) {
|
|
FSItem *item = find_fsitem_by_id(ReadMacInt32(fcb + fcbFlNm));
|
|
if (item) {
|
|
get_path_for_fsitem(item);
|
|
close_rfork(full_path, fd);
|
|
}
|
|
} else
|
|
close(fd);
|
|
WriteMacInt32(fcb + fcbCatPos, (uint32)-1);
|
|
|
|
// Release FCB
|
|
D(bug(" releasing FCB\n"));
|
|
r.d[0] = ReadMacInt16(pb + ioRefNum);
|
|
Execute68k(fs_data + fsReleaseFCB, &r);
|
|
D(bug(" UTReleaseFCB() returned %d\n", r.d[0]));
|
|
return (int16)r.d[0];
|
|
}
|
|
|
|
// Query information about FCB (FCBPBRec)
|
|
static int16 fs_get_fcb_info(uint32 pb, uint32 vcb)
|
|
{
|
|
D(bug(" fs_get_fcb_info(%08lx), vRefNum %d, refNum %d, idx %d\n", pb, ReadMacInt16(pb + ioVRefNum), ReadMacInt16(pb + ioRefNum), ReadMacInt16(pb + ioFCBIndx)));
|
|
M68kRegisters r;
|
|
|
|
uint32 fcb = 0;
|
|
if (ReadMacInt16(pb + ioFCBIndx) == 0) { // Get information about single file
|
|
|
|
// Find FCB for file
|
|
fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
|
|
|
|
} else { // Get information about file specified by index
|
|
|
|
// Find FCB by index
|
|
WriteMacInt16(pb + ioRefNum, 0);
|
|
for (int i=0; i<(int)ReadMacInt16(pb + ioFCBIndx); i++) {
|
|
D(bug(" indexing FCBs\n"));
|
|
r.a[0] = vcb;
|
|
r.a[1] = pb + ioRefNum;
|
|
r.a[2] = fs_data + fsReturn;
|
|
Execute68k(fs_data + fsIndexFCB, &r);
|
|
fcb = ReadMacInt32(fs_data + fsReturn);
|
|
D(bug(" UTIndexFCB() returned %d, fcb %p\n", r.d[0], fcb));
|
|
if (r.d[0] & 0xffff)
|
|
return (int16)r.d[0];
|
|
}
|
|
}
|
|
if (fcb == 0)
|
|
return rfNumErr;
|
|
|
|
// Copy information from FCB
|
|
if (ReadMacInt32(pb + ioNamePtr))
|
|
pstrcpy((char *)Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), (char *)Mac2HostAddr(fcb + fcbCName));
|
|
WriteMacInt32(pb + ioFCBFlNm, ReadMacInt32(fcb + fcbFlNm));
|
|
WriteMacInt8(pb + ioFCBFlags, ReadMacInt8(fcb + fcbFlags));
|
|
WriteMacInt16(pb + ioFCBStBlk, ReadMacInt16(fcb + fcbSBlk));
|
|
WriteMacInt32(pb + ioFCBEOF, ReadMacInt32(fcb + fcbEOF));
|
|
WriteMacInt32(pb + ioFCBPLen, ReadMacInt32(fcb + fcbPLen));
|
|
WriteMacInt32(pb + ioFCBCrPs, ReadMacInt32(fcb + fcbCrPs));
|
|
WriteMacInt16(pb + ioFCBVRefNum, ReadMacInt16(ReadMacInt32(fcb + fcbVPtr) + vcbVRefNum));
|
|
WriteMacInt32(pb + ioFCBClpSiz, ReadMacInt32(fcb + fcbClmpSize));
|
|
WriteMacInt32(pb + ioFCBParID, ReadMacInt32(fcb + fcbDirID));
|
|
return noErr;
|
|
}
|
|
|
|
// Obtain logical size of an open file
|
|
static int16 fs_get_eof(uint32 pb)
|
|
{
|
|
D(bug(" fs_get_eof(%08lx), refNum %d\n", pb, ReadMacInt16(pb + ioRefNum)));
|
|
M68kRegisters r;
|
|
|
|
// Find FCB and fd for file
|
|
uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
|
|
if (fcb == 0)
|
|
return rfNumErr;
|
|
if (ReadMacInt32(fcb + fcbFlNm) == 0)
|
|
return fnOpnErr;
|
|
int fd = ReadMacInt32(fcb + fcbCatPos);
|
|
if (fd < 0) {
|
|
if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork
|
|
WriteMacInt32(pb + ioMisc, 0);
|
|
return noErr;
|
|
} else
|
|
return fnOpnErr;
|
|
}
|
|
|
|
// Get file size
|
|
struct stat st;
|
|
if (fstat(fd, &st) < 0)
|
|
return errno2oserr();
|
|
|
|
// Adjust FCBs
|
|
WriteMacInt32(fcb + fcbEOF, st.st_size);
|
|
WriteMacInt32(fcb + fcbPLen, (st.st_size | (AL_BLK_SIZE - 1)) + 1);
|
|
WriteMacInt32(pb + ioMisc, st.st_size);
|
|
D(bug(" adjusting FCBs\n"));
|
|
r.d[0] = ReadMacInt16(pb + ioRefNum);
|
|
Execute68k(fs_data + fsAdjustEOF, &r);
|
|
D(bug(" UTAdjustEOF() returned %d\n", r.d[0]));
|
|
return noErr;
|
|
}
|
|
|
|
// Truncate file
|
|
static int16 fs_set_eof(uint32 pb)
|
|
{
|
|
D(bug(" fs_set_eof(%08lx), refNum %d, size %d\n", pb, ReadMacInt16(pb + ioRefNum), ReadMacInt32(pb + ioMisc)));
|
|
M68kRegisters r;
|
|
|
|
// Find FCB and fd for file
|
|
uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
|
|
if (fcb == 0)
|
|
return rfNumErr;
|
|
if (ReadMacInt32(fcb + fcbFlNm) == 0)
|
|
return fnOpnErr;
|
|
int fd = ReadMacInt32(fcb + fcbCatPos);
|
|
if (fd < 0) {
|
|
if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) // "pseudo" resource fork
|
|
return noErr;
|
|
else
|
|
return fnOpnErr;
|
|
}
|
|
|
|
// Truncate file
|
|
uint32 size = ReadMacInt32(pb + ioMisc);
|
|
if (ftruncate(fd, size) < 0)
|
|
return errno2oserr();
|
|
|
|
// Adjust FCBs
|
|
WriteMacInt32(fcb + fcbEOF, size);
|
|
WriteMacInt32(fcb + fcbPLen, (size | (AL_BLK_SIZE - 1)) + 1);
|
|
D(bug(" adjusting FCBs\n"));
|
|
r.d[0] = ReadMacInt16(pb + ioRefNum);
|
|
Execute68k(fs_data + fsAdjustEOF, &r);
|
|
D(bug(" UTAdjustEOF() returned %d\n", r.d[0]));
|
|
return noErr;
|
|
}
|
|
|
|
// Query current file position
|
|
static int16 fs_get_fpos(uint32 pb)
|
|
{
|
|
D(bug(" fs_get_fpos(%08lx), refNum %d\n", pb, ReadMacInt16(pb + ioRefNum)));
|
|
|
|
WriteMacInt32(pb + ioReqCount, 0);
|
|
WriteMacInt32(pb + ioActCount, 0);
|
|
WriteMacInt16(pb + ioPosMode, 0);
|
|
|
|
// Find FCB and fd for file
|
|
uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
|
|
if (fcb == 0)
|
|
return rfNumErr;
|
|
if (ReadMacInt32(fcb + fcbFlNm) == 0)
|
|
return fnOpnErr;
|
|
int fd = ReadMacInt32(fcb + fcbCatPos);
|
|
if (fd < 0) {
|
|
if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork
|
|
WriteMacInt32(pb + ioPosOffset, 0);
|
|
return noErr;
|
|
} else
|
|
return fnOpnErr;
|
|
}
|
|
|
|
// Get file position
|
|
uint32 pos = lseek(fd, 0, SEEK_CUR);
|
|
WriteMacInt32(fcb + fcbCrPs, pos);
|
|
WriteMacInt32(pb + ioPosOffset, pos);
|
|
return noErr;
|
|
}
|
|
|
|
// Set current file position
|
|
static int16 fs_set_fpos(uint32 pb)
|
|
{
|
|
D(bug(" fs_set_fpos(%08lx), refNum %d, posMode %d, offset %d\n", pb, ReadMacInt16(pb + ioRefNum), ReadMacInt16(pb + ioPosMode), ReadMacInt32(pb + ioPosOffset)));
|
|
|
|
// Find FCB and fd for file
|
|
uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
|
|
if (fcb == 0)
|
|
return rfNumErr;
|
|
if (ReadMacInt32(fcb + fcbFlNm) == 0)
|
|
return fnOpnErr;
|
|
int fd = ReadMacInt32(fcb + fcbCatPos);
|
|
if (fd < 0) {
|
|
if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork
|
|
WriteMacInt32(pb + ioPosOffset, 0);
|
|
return noErr;
|
|
} else
|
|
return fnOpnErr;
|
|
}
|
|
|
|
// Set file position
|
|
switch (ReadMacInt16(pb + ioPosMode) & 3) {
|
|
case fsFromStart:
|
|
if (lseek(fd, ReadMacInt32(pb + ioPosOffset), SEEK_SET) < 0)
|
|
return posErr;
|
|
break;
|
|
case fsFromLEOF:
|
|
if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_END) < 0)
|
|
return posErr;
|
|
break;
|
|
case fsFromMark:
|
|
if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_CUR) < 0)
|
|
return posErr;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
uint32 pos = lseek(fd, 0, SEEK_CUR);
|
|
WriteMacInt32(fcb + fcbCrPs, pos);
|
|
WriteMacInt32(pb + ioPosOffset, pos);
|
|
return noErr;
|
|
}
|
|
|
|
// Read from file
|
|
static int16 fs_read(uint32 pb)
|
|
{
|
|
D(bug(" fs_read(%08lx), refNum %d, buffer %p, count %d, posMode %d, posOffset %d\n", pb, ReadMacInt16(pb + ioRefNum), ReadMacInt32(pb + ioBuffer), ReadMacInt32(pb + ioReqCount), ReadMacInt16(pb + ioPosMode), ReadMacInt32(pb + ioPosOffset)));
|
|
|
|
// Check parameters
|
|
if ((int32)ReadMacInt32(pb + ioReqCount) < 0)
|
|
return paramErr;
|
|
|
|
// Find FCB and fd for file
|
|
uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
|
|
if (fcb == 0)
|
|
return rfNumErr;
|
|
if (ReadMacInt32(fcb + fcbFlNm) == 0)
|
|
return fnOpnErr;
|
|
int fd = ReadMacInt32(fcb + fcbCatPos);
|
|
if (fd < 0) {
|
|
if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork
|
|
WriteMacInt32(pb + ioActCount, 0);
|
|
return eofErr;
|
|
} else
|
|
return fnOpnErr;
|
|
}
|
|
|
|
// Seek
|
|
switch (ReadMacInt16(pb + ioPosMode) & 3) {
|
|
case fsFromStart:
|
|
if (lseek(fd, ReadMacInt32(pb + ioPosOffset), SEEK_SET) < 0)
|
|
return posErr;
|
|
break;
|
|
case fsFromLEOF:
|
|
if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_END) < 0)
|
|
return posErr;
|
|
break;
|
|
case fsFromMark:
|
|
if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_CUR) < 0)
|
|
return posErr;
|
|
break;
|
|
}
|
|
|
|
// Read
|
|
ssize_t actual = extfs_read(fd, Mac2HostAddr(ReadMacInt32(pb + ioBuffer)), ReadMacInt32(pb + ioReqCount));
|
|
int16 read_err = errno2oserr();
|
|
D(bug(" actual %d\n", actual));
|
|
WriteMacInt32(pb + ioActCount, actual >= 0 ? actual : 0);
|
|
uint32 pos = lseek(fd, 0, SEEK_CUR);
|
|
WriteMacInt32(fcb + fcbCrPs, pos);
|
|
WriteMacInt32(pb + ioPosOffset, pos);
|
|
if (actual != (ssize_t)ReadMacInt32(pb + ioReqCount))
|
|
return actual < 0 ? read_err : eofErr;
|
|
else
|
|
return noErr;
|
|
}
|
|
|
|
// Write to file
|
|
static int16 fs_write(uint32 pb)
|
|
{
|
|
D(bug(" fs_write(%08lx), refNum %d, buffer %p, count %d, posMode %d, posOffset %d\n", pb, ReadMacInt16(pb + ioRefNum), ReadMacInt32(pb + ioBuffer), ReadMacInt32(pb + ioReqCount), ReadMacInt16(pb + ioPosMode), ReadMacInt32(pb + ioPosOffset)));
|
|
|
|
// Check parameters
|
|
if ((int32)ReadMacInt32(pb + ioReqCount) < 0)
|
|
return paramErr;
|
|
|
|
// Find FCB and fd for file
|
|
uint32 fcb = find_fcb(ReadMacInt16(pb + ioRefNum));
|
|
if (fcb == 0)
|
|
return rfNumErr;
|
|
if (ReadMacInt32(fcb + fcbFlNm) == 0)
|
|
return fnOpnErr;
|
|
int fd = ReadMacInt32(fcb + fcbCatPos);
|
|
if (fd < 0) {
|
|
if (ReadMacInt8(fcb + fcbFlags) & fcbResourceMask) { // "pseudo" resource fork
|
|
WriteMacInt32(pb + ioActCount, ReadMacInt32(pb + ioReqCount));
|
|
return noErr;
|
|
} else
|
|
return fnOpnErr;
|
|
}
|
|
|
|
// Seek
|
|
switch (ReadMacInt16(pb + ioPosMode) & 3) {
|
|
case fsFromStart:
|
|
if (lseek(fd, ReadMacInt32(pb + ioPosOffset), SEEK_SET) < 0)
|
|
return posErr;
|
|
break;
|
|
case fsFromLEOF:
|
|
if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_END) < 0)
|
|
return posErr;
|
|
break;
|
|
case fsFromMark:
|
|
if (lseek(fd, (int32)ReadMacInt32(pb + ioPosOffset), SEEK_CUR) < 0)
|
|
return posErr;
|
|
break;
|
|
}
|
|
|
|
// Write
|
|
ssize_t actual = extfs_write(fd, Mac2HostAddr(ReadMacInt32(pb + ioBuffer)), ReadMacInt32(pb + ioReqCount));
|
|
int16 write_err = errno2oserr();
|
|
D(bug(" actual %d\n", actual));
|
|
WriteMacInt32(pb + ioActCount, actual >= 0 ? actual : 0);
|
|
uint32 pos = lseek(fd, 0, SEEK_CUR);
|
|
WriteMacInt32(fcb + fcbCrPs, pos);
|
|
WriteMacInt32(pb + ioPosOffset, pos);
|
|
if (actual != (ssize_t)ReadMacInt32(pb + ioReqCount))
|
|
return write_err;
|
|
else
|
|
return noErr;
|
|
}
|
|
|
|
// Create file
|
|
static int16 fs_create(uint32 pb, uint32 dirID)
|
|
{
|
|
D(bug(" fs_create(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID));
|
|
|
|
// Find FSItem for given file
|
|
FSItem *fs_item;
|
|
int16 result = get_item_and_path(pb, dirID, fs_item);
|
|
if (result != noErr)
|
|
return result;
|
|
|
|
// Does the file already exist?
|
|
if (access(full_path, F_OK) == 0)
|
|
return dupFNErr;
|
|
|
|
// Create file
|
|
int fd = creat(full_path, 0666);
|
|
if (fd < 0)
|
|
return errno2oserr();
|
|
else {
|
|
close(fd);
|
|
return noErr;
|
|
}
|
|
}
|
|
|
|
// Create directory
|
|
static int16 fs_dir_create(uint32 pb)
|
|
{
|
|
D(bug(" fs_dir_create(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt32(pb + ioDirID)));
|
|
|
|
// Find FSItem for given directory
|
|
FSItem *fs_item;
|
|
int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item);
|
|
if (result != noErr)
|
|
return result;
|
|
|
|
// Does the directory already exist?
|
|
if (access(full_path, F_OK) == 0)
|
|
return dupFNErr;
|
|
|
|
// Create directory
|
|
if (mkdir(full_path, 0777) < 0)
|
|
return errno2oserr();
|
|
else {
|
|
WriteMacInt32(pb + ioDirID, fs_item->id);
|
|
return noErr;
|
|
}
|
|
}
|
|
|
|
// Delete file/directory
|
|
static int16 fs_delete(uint32 pb, uint32 dirID)
|
|
{
|
|
D(bug(" fs_delete(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID));
|
|
|
|
// Find FSItem for given file/dir
|
|
FSItem *fs_item;
|
|
int16 result = get_item_and_path(pb, dirID, fs_item);
|
|
if (result != noErr)
|
|
return result;
|
|
|
|
// Delete file
|
|
if (!extfs_remove(full_path))
|
|
return errno2oserr();
|
|
else
|
|
return noErr;
|
|
}
|
|
|
|
// Rename file/directory
|
|
static int16 fs_rename(uint32 pb, uint32 dirID)
|
|
{
|
|
D(bug(" fs_rename(%08lx), vRefNum %d, name %.31s, dirID %d, new name %.31s\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), dirID, Mac2HostAddr(ReadMacInt32(pb + ioMisc) + 1)));
|
|
|
|
// Find path of given file/dir
|
|
FSItem *fs_item;
|
|
int16 result = get_item_and_path(pb, dirID, fs_item);
|
|
if (result != noErr)
|
|
return result;
|
|
|
|
// Save path of existing item
|
|
char old_path[MAX_PATH_LENGTH];
|
|
strcpy(old_path, full_path);
|
|
|
|
// Find path for new name
|
|
Mac2Mac_memcpy(fs_data + fsPB, pb, SIZEOF_IOParam);
|
|
WriteMacInt32(fs_data + fsPB + ioNamePtr, ReadMacInt32(pb + ioMisc));
|
|
FSItem *new_item;
|
|
result = get_item_and_path(fs_data + fsPB, dirID, new_item);
|
|
if (result != noErr)
|
|
return result;
|
|
|
|
// Does the new name already exist?
|
|
if (access(full_path, F_OK) == 0)
|
|
return dupFNErr;
|
|
|
|
// Rename item
|
|
D(bug(" renaming %s -> %s\n", old_path, full_path));
|
|
if (!extfs_rename(old_path, full_path))
|
|
return errno2oserr();
|
|
else {
|
|
// The ID of the old file/dir has to stay the same, so we swap the IDs of the FSItems
|
|
swap_parent_ids(fs_item->id, new_item->id);
|
|
uint32 t = fs_item->id;
|
|
fs_item->id = new_item->id;
|
|
new_item->id = t;
|
|
return noErr;
|
|
}
|
|
}
|
|
|
|
// Move file/directory (CMovePBRec)
|
|
static int16 fs_cat_move(uint32 pb)
|
|
{
|
|
D(bug(" fs_cat_move(%08lx), vRefNum %d, name %.31s, dirID %d, new name %.31s, new dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt32(pb + ioDirID), Mac2HostAddr(ReadMacInt32(pb + ioNewName) + 1), ReadMacInt32(pb + ioNewDirID)));
|
|
|
|
// Find path of given file/dir
|
|
FSItem *fs_item;
|
|
int16 result = get_item_and_path(pb, ReadMacInt32(pb + ioDirID), fs_item);
|
|
if (result != noErr)
|
|
return result;
|
|
|
|
// Save path of existing item
|
|
char old_path[MAX_PATH_LENGTH];
|
|
strcpy(old_path, full_path);
|
|
|
|
// Find path for new directory
|
|
Mac2Mac_memcpy(fs_data + fsPB, pb, SIZEOF_IOParam);
|
|
WriteMacInt32(fs_data + fsPB + ioNamePtr, ReadMacInt32(pb + ioNewName));
|
|
FSItem *new_dir_item;
|
|
result = get_item_and_path(fs_data + fsPB, ReadMacInt32(pb + ioNewDirID), new_dir_item);
|
|
if (result != noErr)
|
|
return result;
|
|
|
|
// Append old file/dir name
|
|
add_path_comp(fs_item->name);
|
|
|
|
// Does the new name already exist?
|
|
if (access(full_path, F_OK) == 0)
|
|
return dupFNErr;
|
|
|
|
// Move item
|
|
D(bug(" moving %s -> %s\n", old_path, full_path));
|
|
if (!extfs_rename(old_path, full_path))
|
|
return errno2oserr();
|
|
else {
|
|
// The ID of the old file/dir has to stay the same, so we swap the IDs of the FSItems
|
|
FSItem *new_item = find_fsitem(fs_item->name, new_dir_item);
|
|
if (new_item) {
|
|
swap_parent_ids(fs_item->id, new_item->id);
|
|
uint32 t = fs_item->id;
|
|
fs_item->id = new_item->id;
|
|
new_item->id = t;
|
|
}
|
|
return noErr;
|
|
}
|
|
}
|
|
|
|
// Open working directory (WDParam)
|
|
static int16 fs_open_wd(uint32 pb)
|
|
{
|
|
D(bug(" fs_open_wd(%08lx), vRefNum %d, name %.31s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr) + 1), ReadMacInt32(pb + ioWDDirID)));
|
|
M68kRegisters r;
|
|
|
|
// Allocate WDCB
|
|
D(bug(" allocating WDCB\n"));
|
|
r.a[0] = pb;
|
|
Execute68k(fs_data + fsAllocateWDCB, &r);
|
|
D(bug(" UTAllocateWDCB returned %d, refNum is %d\n", r.d[0], ReadMacInt16(pb + ioVRefNum)));
|
|
return (int16)r.d[0];
|
|
}
|
|
|
|
// Close working directory (WDParam)
|
|
static int16 fs_close_wd(uint32 pb)
|
|
{
|
|
D(bug(" fs_close_wd(%08lx), vRefNum %d\n", pb, ReadMacInt16(pb + ioVRefNum)));
|
|
M68kRegisters r;
|
|
|
|
// Release WDCB
|
|
D(bug(" releasing WDCB\n"));
|
|
r.d[0] = ReadMacInt16(pb + ioVRefNum);
|
|
Execute68k(fs_data + fsReleaseWDCB, &r);
|
|
D(bug(" UTReleaseWDCB returned %d\n", r.d[0]));
|
|
return (int16)r.d[0];
|
|
}
|
|
|
|
// Query information about working directory (WDParam)
|
|
static int16 fs_get_wd_info(uint32 pb, uint32 vcb)
|
|
{
|
|
D(bug(" fs_get_wd_info(%08lx), vRefNum %d, idx %d, procID %d\n", pb, ReadMacInt16(pb + ioVRefNum), ReadMacInt16(pb + ioWDIndex), ReadMacInt32(pb + ioWDProcID)));
|
|
M68kRegisters r;
|
|
|
|
// Querying volume?
|
|
if (ReadMacInt16(pb + ioWDIndex) == 0 && ReadMacInt16(pb + ioVRefNum) == ReadMacInt16(vcb + vcbVRefNum)) {
|
|
WriteMacInt32(pb + ioWDProcID, 0);
|
|
WriteMacInt16(pb + ioWDVRefNum, ReadMacInt16(vcb + vcbVRefNum));
|
|
if (ReadMacInt32(pb + ioNamePtr))
|
|
Mac2Mac_memcpy(ReadMacInt32(pb + ioNamePtr), vcb + vcbVN, 28);
|
|
WriteMacInt32(pb + ioWDDirID, ROOT_ID);
|
|
return noErr;
|
|
}
|
|
|
|
// Resolve WDCB
|
|
D(bug(" resolving WDCB\n"));
|
|
r.d[0] = ReadMacInt32(pb + ioWDProcID);
|
|
r.d[1] = ReadMacInt16(pb + ioWDIndex);
|
|
r.d[2] = ReadMacInt16(pb + ioVRefNum);
|
|
r.a[0] = fs_data + fsReturn;
|
|
Execute68k(fs_data + fsResolveWDCB, &r);
|
|
uint32 wdcb = ReadMacInt32(fs_data + fsReturn);
|
|
D(bug(" UTResolveWDCB() returned %d, dirID %d\n", r.d[0], ReadMacInt32(wdcb + wdDirID)));
|
|
if (r.d[0] & 0xffff)
|
|
return (int16)r.d[0];
|
|
|
|
// Return information
|
|
WriteMacInt32(pb + ioWDProcID, ReadMacInt32(wdcb + wdProcID));
|
|
WriteMacInt16(pb + ioWDVRefNum, ReadMacInt16(ReadMacInt32(wdcb + wdVCBPtr) + vcbVRefNum));
|
|
if (ReadMacInt32(pb + ioNamePtr))
|
|
Mac2Mac_memcpy(ReadMacInt32(pb + ioNamePtr), ReadMacInt32(wdcb + wdVCBPtr) + vcbVN, 28);
|
|
WriteMacInt32(pb + ioWDDirID, ReadMacInt32(wdcb + wdDirID));
|
|
return noErr;
|
|
}
|
|
|
|
// Main dispatch routine
|
|
int16 ExtFSHFS(uint32 vcb, uint16 selectCode, uint32 paramBlock, uint32 globalsPtr, int16 fsid)
|
|
{
|
|
uint16 trapWord = selectCode & 0xf0ff;
|
|
bool hfs = (selectCode & kHFSMask) != 0;
|
|
switch (trapWord) {
|
|
case kFSMOpen:
|
|
return fs_open(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0, vcb, false);
|
|
|
|
case kFSMClose:
|
|
return fs_close(paramBlock);
|
|
|
|
case kFSMRead:
|
|
return fs_read(paramBlock);
|
|
|
|
case kFSMWrite:
|
|
return fs_write(paramBlock);
|
|
|
|
case kFSMGetVolInfo:
|
|
return fs_get_vol_info(paramBlock, hfs);
|
|
|
|
case kFSMCreate:
|
|
return fs_create(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
|
|
|
|
case kFSMDelete:
|
|
return fs_delete(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
|
|
|
|
case kFSMOpenRF:
|
|
return fs_open(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0, vcb, true);
|
|
|
|
case kFSMRename:
|
|
return fs_rename(paramBlock, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
|
|
|
|
case kFSMGetFileInfo:
|
|
return fs_get_file_info(paramBlock, hfs, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
|
|
|
|
case kFSMSetFileInfo:
|
|
return fs_set_file_info(paramBlock, hfs, hfs ? ReadMacInt32(paramBlock + ioDirID) : 0);
|
|
|
|
case kFSMUnmountVol:
|
|
return fs_unmount_vol(vcb);
|
|
|
|
case kFSMMountVol:
|
|
return fs_mount_vol(paramBlock);
|
|
|
|
case kFSMAllocate:
|
|
D(bug(" allocate\n"));
|
|
WriteMacInt32(paramBlock + ioActCount, ReadMacInt32(paramBlock + ioReqCount));
|
|
return noErr;
|
|
|
|
case kFSMGetEOF:
|
|
return fs_get_eof(paramBlock);
|
|
|
|
case kFSMSetEOF:
|
|
return fs_set_eof(paramBlock);
|
|
|
|
case kFSMGetVol:
|
|
return fs_get_vol(paramBlock);
|
|
|
|
case kFSMSetVol:
|
|
return fs_set_vol(paramBlock, hfs, vcb);
|
|
|
|
case kFSMEject:
|
|
D(bug(" eject\n"));
|
|
return noErr;
|
|
|
|
case kFSMGetFPos:
|
|
return fs_get_fpos(paramBlock);
|
|
|
|
case kFSMOffline:
|
|
D(bug(" offline\n"));
|
|
return noErr;
|
|
|
|
case kFSMSetFilLock:
|
|
return noErr; //!!
|
|
|
|
case kFSMRstFilLock:
|
|
return noErr; //!!
|
|
|
|
case kFSMSetFPos:
|
|
return fs_set_fpos(paramBlock);
|
|
|
|
case kFSMOpenWD:
|
|
return fs_open_wd(paramBlock);
|
|
|
|
case kFSMCloseWD:
|
|
return fs_close_wd(paramBlock);
|
|
|
|
case kFSMCatMove:
|
|
return fs_cat_move(paramBlock);
|
|
|
|
case kFSMDirCreate:
|
|
return fs_dir_create(paramBlock);
|
|
|
|
case kFSMGetWDInfo:
|
|
return fs_get_wd_info(paramBlock, vcb);
|
|
|
|
case kFSMGetFCBInfo:
|
|
return fs_get_fcb_info(paramBlock, vcb);
|
|
|
|
case kFSMGetCatInfo:
|
|
return fs_get_cat_info(paramBlock);
|
|
|
|
case kFSMSetCatInfo:
|
|
return fs_set_cat_info(paramBlock);
|
|
|
|
case kFSMSetVolInfo:
|
|
return fs_set_vol_info(paramBlock);
|
|
|
|
case kFSMGetVolParms:
|
|
return fs_get_vol_parms(paramBlock);
|
|
|
|
case kFSMVolumeMount:
|
|
return fs_volume_mount(paramBlock);
|
|
|
|
case kFSMFlushVol:
|
|
case kFSMFlushFile:
|
|
D(bug(" flush_vol/flush_file\n"));
|
|
return noErr;
|
|
|
|
default:
|
|
D(bug("ExtFSHFS(%08lx, %04x, %08lx, %08lx, %d)\n", vcb, selectCode, paramBlock, globalsPtr, fsid));
|
|
return paramErr;
|
|
}
|
|
}
|