From d92b13e5506841646a62b2078858b37884d60f3d Mon Sep 17 00:00:00 2001 From: cebix <> Date: Tue, 19 Oct 1999 17:41:44 +0000 Subject: [PATCH] - added external file system - moved most init/deinit code to InitAll()/ExitAll() in main.cpp --- BasiliskII/ChangeLog | 10 +- BasiliskII/src/AmigaOS/main_amiga.cpp | 76 +- BasiliskII/src/AmigaOS/smakefile | 8 +- BasiliskII/src/AmigaOS/sysdeps.h | 3 + BasiliskII/src/AmigaOS/timer_amiga.cpp | 2 - BasiliskII/src/AmigaOS/user_strings_amiga.cpp | 3 + BasiliskII/src/BeOS/Makefile | 12 +- BasiliskII/src/BeOS/extfs_beos.cpp | 437 ++++ BasiliskII/src/BeOS/main_beos.cpp | 122 +- BasiliskII/src/BeOS/prefs_beos.cpp | 1 + BasiliskII/src/BeOS/sysdeps.h | 3 + BasiliskII/src/BeOS/timer_beos.cpp | 2 - BasiliskII/src/BeOS/user_strings_beos.cpp | 3 + BasiliskII/src/Unix/Makefile.in | 10 +- BasiliskII/src/Unix/extfs_unix.cpp | 200 ++ BasiliskII/src/Unix/main_unix.cpp | 114 +- BasiliskII/src/Unix/prefs_editor_gtk.cpp | 6 +- BasiliskII/src/Unix/prefs_unix.cpp | 1 + BasiliskII/src/Unix/sysdeps.h | 3 + BasiliskII/src/Unix/timer_unix.cpp | 2 - BasiliskII/src/Unix/user_strings_unix.cpp | 3 + BasiliskII/src/emul_op.cpp | 9 + BasiliskII/src/extfs.cpp | 2166 +++++++++++++++++ BasiliskII/src/include/emul_op.h | 2 + BasiliskII/src/include/extfs.h | 45 + BasiliskII/src/include/extfs_defs.h | 559 +++++ BasiliskII/src/include/macos_util.h | 20 +- BasiliskII/src/include/main.h | 6 +- BasiliskII/src/include/user_strings.h | 7 +- BasiliskII/src/main.cpp | 170 ++ BasiliskII/src/prefs.cpp | 1 + BasiliskII/src/rom_patches.cpp | 10 +- BasiliskII/src/user_strings.cpp | 4 + 33 files changed, 3697 insertions(+), 323 deletions(-) create mode 100644 BasiliskII/src/BeOS/extfs_beos.cpp create mode 100644 BasiliskII/src/Unix/extfs_unix.cpp create mode 100644 BasiliskII/src/extfs.cpp create mode 100644 BasiliskII/src/include/extfs.h create mode 100644 BasiliskII/src/include/extfs_defs.h create mode 100644 BasiliskII/src/main.cpp diff --git a/BasiliskII/ChangeLog b/BasiliskII/ChangeLog index 3716bc81..f0db2122 100644 --- a/BasiliskII/ChangeLog +++ b/BasiliskII/ChangeLog @@ -3,11 +3,17 @@ V0.7 - by an interrupt routine - localizable strings are now split into a common and a platform- specific set - - AmigaOS/clip_amiga.cpp: fixed small bug in CR->LF translation - [Giacomo Magnini] + - added external file system to access host OS files from the MacOS; + root directory is specified by the "extfs" prefs item + - moved most initialization/deinitialization code to InitAll() and + ExitAll() in main.cpp - added patches for NetBSD [Bernd Sieker] - corrected TimerDateTime() in timer_unix.cpp and timer_beos.cpp [Toshimitsu Tanaka] + - AmigaOS/clip_amiga.cpp: fixed small bug in CR->LF translation + [Giacomo Magnini] + - Unix: compilation of cpuemu.cpp is now split in 8 parts + - Unix: volume list in GTK prefs editor is reorderable V0.7 (release 0.7-2) - 6.Oct.1999 - Added BasiliskII.spec for making RPMs [with assistance from diff --git a/BasiliskII/src/AmigaOS/main_amiga.cpp b/BasiliskII/src/AmigaOS/main_amiga.cpp index a846f0df..cd81c21a 100644 --- a/BasiliskII/src/AmigaOS/main_amiga.cpp +++ b/BasiliskII/src/AmigaOS/main_amiga.cpp @@ -248,60 +248,16 @@ int main(void) QuitEmulator(); } - // Check ROM version - if (!CheckROM()) { - ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR)); - QuitEmulator(); - } - // Set CPU and FPU type UWORD attn = SysBase->AttnFlags; CPUType = attn & AFF_68040 ? 4 : (attn & AFF_68030 ? 3 : 2); CPUIs68060 = attn & AFF_68060; FPUType = attn & AFF_68881 ? 1 : 0; - // Load XPRAM - XPRAMInit(); - - // Set boot volume - int16 i16 = PrefsFindInt16("bootdrive"); - XPRAM[0x78] = i16 >> 8; - XPRAM[0x79] = i16 & 0xff; - i16 = PrefsFindInt16("bootdriver"); - XPRAM[0x7a] = i16 >> 8; - XPRAM[0x7b] = i16 & 0xff; - - // Init drivers - SonyInit(); - DiskInit(); - CDROMInit(); - SCSIInit(); - - // Init network - EtherInit(); - - // Init serial ports - SerialInit(); - - // Init Time Manager - TimerInit(); - - // Init clipboard - ClipInit(); - - // Init audio - AudioInit(); - - // Init video - if (!VideoInit(ROMVersion == ROM_VERSION_64K || ROMVersion == ROM_VERSION_PLUS || ROMVersion == ROM_VERSION_CLASSIC)) + // Initialize everything + if (!InitAll()) QuitEmulator(); - // Install ROM patches - if (!PatchROM()) { - ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR)); - QuitEmulator(); - } - // Move VBR away from 0 if neccessary MoveVBR(); @@ -379,32 +335,8 @@ void __saveds QuitEmulator(void) // Remove trap handler MainTask->tc_TrapCode = OldTrapHandler; - // Save XPRAM - XPRAMExit(); - - // Exit video - VideoExit(); - - // Exit audio - AudioExit(); - - // Exit clipboard - ClipExit(); - - // Exit Time Manager - TimerExit(); - - // Exit serial ports - SerialExit(); - - // Exit network - EtherExit(); - - // Exit drivers - SCSIExit(); - CDROMExit(); - DiskExit(); - SonyExit(); + // Deinitialize everything + ExitAll(); // Delete RAM/ROM area if (RAMBaseHost) diff --git a/BasiliskII/src/AmigaOS/smakefile b/BasiliskII/src/AmigaOS/smakefile index 1fb79f94..31aa1223 100644 --- a/BasiliskII/src/AmigaOS/smakefile +++ b/BasiliskII/src/AmigaOS/smakefile @@ -9,9 +9,9 @@ LIBS = LIB lib:debug.lib AFLAGS = CPU=68020 ## Files -OBJS = prefs.o rom_patches.o slot_rom.o rsrc_patches.o emul_op.o macos_util.o \ +OBJS = main.o prefs.o rom_patches.o slot_rom.o rsrc_patches.o emul_op.o macos_util.o \ xpram.o timer.o adb.o serial.o ether.o sony.o disk.o cdrom.o scsi.o \ - video.o audio.o user_strings.o \ + video.o audio.o extfs.o user_strings.o \ main_amiga.o asm_support.o prefs_amiga.o prefs_editor_amiga.o \ sys_amiga.o xpram_amiga.o timer_amiga.o clip_amiga.o serial_amiga.o \ ether_amiga.o scsi_amiga.o audio_amiga.o video_amiga.o user_strings_amiga.o @@ -24,6 +24,8 @@ $(APP): $(OBJS) clean: -delete $(APP) $(OBJS) +main.o: /main.cpp + $(CC) $(INCLUDES) $(CFLAGS) /main.cpp prefs.o: /prefs.cpp $(CC) $(INCLUDES) $(CFLAGS) /prefs.cpp rom_patches.o: /rom_patches.cpp @@ -58,6 +60,8 @@ video.o: /video.cpp $(CC) $(INCLUDES) $(CFLAGS) /video.cpp audio.o: /audio.cpp $(CC) $(INCLUDES) $(CFLAGS) /audio.cpp +extfs.o: /extfs.cpp + $(CC) $(INCLUDES) $(CFLAGS) /extfs.cpp user_strings.o: /user_strings.cpp $(CC) $(INCLUDES) $(CFLAGS) /user_strings.cpp diff --git a/BasiliskII/src/AmigaOS/sysdeps.h b/BasiliskII/src/AmigaOS/sysdeps.h index 3ccea950..3e33b16c 100644 --- a/BasiliskII/src/AmigaOS/sysdeps.h +++ b/BasiliskII/src/AmigaOS/sysdeps.h @@ -54,6 +54,9 @@ typedef LONG loff_t; // Time data type for Time Manager emulation typedef struct timeval tm_time_t; +// Offset Mac->AmigaOS time in seconds +#define TIME_OFFSET 0x8b31ef80 + // Endianess conversion (not needed) #define ntohs(x) (x) #define ntohl(x) (x) diff --git a/BasiliskII/src/AmigaOS/timer_amiga.cpp b/BasiliskII/src/AmigaOS/timer_amiga.cpp index 2d8533fa..099c8fb1 100644 --- a/BasiliskII/src/AmigaOS/timer_amiga.cpp +++ b/BasiliskII/src/AmigaOS/timer_amiga.cpp @@ -52,8 +52,6 @@ void Microseconds(uint32 &hi, uint32 &lo) * Return local date/time in Mac format (seconds since 1.1.1904) */ -const uint32 TIME_OFFSET = 0x8b31ef80; // Offset Mac->Amiga time in seconds - uint32 TimerDateTime(void) { ULONG secs; diff --git a/BasiliskII/src/AmigaOS/user_strings_amiga.cpp b/BasiliskII/src/AmigaOS/user_strings_amiga.cpp index acf968a1..c75feb86 100644 --- a/BasiliskII/src/AmigaOS/user_strings_amiga.cpp +++ b/BasiliskII/src/AmigaOS/user_strings_amiga.cpp @@ -26,6 +26,9 @@ user_string_def platform_strings[] = { // Common strings that have a platform-specific variant {STR_VOLUME_IS_MOUNTED_WARN, "The volume '%s' is mounted under AmigaOS. Basilisk II will try to unmount it."}, + {STR_EXTFS_CTRL, "Amiga Root"}, + {STR_EXTFS_NAME, "Amiga Directory Tree"}, + {STR_EXTFS_VOLUME_NAME, "Amiga"}, // Purely platform-specific strings {STR_NO_PREPARE_EMUL_ERR, "PrepareEmul is not installed. Run PrepareEmul and then try again to start Basilisk II."}, diff --git a/BasiliskII/src/BeOS/Makefile b/BasiliskII/src/BeOS/Makefile index deb28ccb..a6c53e6a 100644 --- a/BasiliskII/src/BeOS/Makefile +++ b/BasiliskII/src/BeOS/Makefile @@ -39,13 +39,13 @@ else CPUSRCS = ../uae_cpu/basilisk_glue.cpp ../uae_cpu/newcpu.cpp \ ../uae_cpu/readcpu.cpp ../uae_cpu/fpp.cpp cpustbl.cpp cpudefs.cpp cpuemu.cpp endif -SRCS = main_beos.cpp ../prefs.cpp prefs_beos.cpp prefs_editor_beos.cpp sys_beos.cpp \ - ../rom_patches.cpp ../slot_rom.cpp ../rsrc_patches.cpp ../emul_op.cpp \ - ../macos_util.cpp ../xpram.cpp xpram_beos.cpp ../timer.cpp timer_beos.cpp \ - clip_beos.cpp ../adb.cpp ../serial.cpp serial_beos.cpp ../ether.cpp \ - ether_beos.cpp ../sony.cpp ../disk.cpp ../cdrom.cpp ../scsi.cpp \ +SRCS = ../main.cpp main_beos.cpp ../prefs.cpp prefs_beos.cpp prefs_editor_beos.cpp \ + sys_beos.cpp ../rom_patches.cpp ../slot_rom.cpp ../rsrc_patches.cpp \ + ../emul_op.cpp ../macos_util.cpp ../xpram.cpp xpram_beos.cpp ../timer.cpp \ + timer_beos.cpp clip_beos.cpp ../adb.cpp ../serial.cpp serial_beos.cpp \ + ../ether.cpp ether_beos.cpp ../sony.cpp ../disk.cpp ../cdrom.cpp ../scsi.cpp \ scsi_beos.cpp ../video.cpp video_beos.cpp ../audio.cpp audio_beos.cpp \ - ../user_strings.cpp user_strings_beos.cpp \ + ../extfs.cpp extfs_beos.cpp ../user_strings.cpp user_strings_beos.cpp \ $(CPUSRCS) # specify the resource files to use diff --git a/BasiliskII/src/BeOS/extfs_beos.cpp b/BasiliskII/src/BeOS/extfs_beos.cpp new file mode 100644 index 00000000..b4dec37f --- /dev/null +++ b/BasiliskII/src/BeOS/extfs_beos.cpp @@ -0,0 +1,437 @@ +/* + * extfs_beos.cpp - MacOS file system for access native file system access, BeOS specific stuff + * + * Basilisk II (C) 1997-1999 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "sysdeps.h" +#include "extfs.h" +#include "extfs_defs.h" + +#define DEBUG 0 +#include "debug.h" + + +// Default Finder flags +const uint16 DEFAULT_FINDER_FLAGS = kHasBeenInited; + +// Temporary buffer for transfers from/to kernel space +const int TMP_BUF_SIZE = 0x10000; +static uint8 *tmp_buf = NULL; + + +/* + * Initialization + */ + +void extfs_init(void) +{ + // Allocate temporary buffer + tmp_buf = new uint8[TMP_BUF_SIZE]; +} + + +/* + * Deinitialization + */ + +void extfs_exit(void) +{ + // Delete temporary buffer + delete[] tmp_buf; +} + + +/* + * Get/set finder type/creator for file specified by full path + */ + +struct mime2type { + const char *mime; + uint32 type; + uint32 creator; + bool reversible; // type -> mime translation possible +}; + +static const mime2type m2t_translation[] = { + {"application/x-compress", 'ZIVM', 'LZIV', true}, + {"application/x-gzip", 'Gzip', 'Gzip', true}, + {"application/x-macbinary", 'BINA', '????', false}, + {"application/mac-binhex40", 'TEXT', 'SITx', false}, + {"application/pdf", 'PDF ', 'CARO', true}, + {"application/postscript", 'TEXT', 'ttxt', false}, + {"application/x-stuffit", 'SIT!', 'SITx', true}, + {"application/x-tar", 'TARF', 'TAR ', true}, + {"application/x-uuencode", 'TEXT', 'SITx', false}, + {"application/zip", 'ZIP ', 'ZIP ', true}, + {"audio/x-8svx", '8SVX', 'SNDM', true}, + {"audio/x-aifc", 'AIFC', 'TVOD', true}, + {"audio/x-aiff", 'AIFF', 'TVOD', true}, + {"audio/basic", 'ULAW', 'TVOD', true}, + {"audio/x-midi", 'MIDI', 'TVOD', true}, + {"audio/x-mpeg", 'MPG ', 'TVOD', true}, + {"audio/x-wav", 'WAVE', 'TVOD', true}, + {"image/x-bmp", 'BMPf', 'ogle', true}, + {"image/gif", 'GIFf', 'ogle', true}, + {"image/x-ilbm", 'ILBM', 'GKON', true}, + {"image/jpeg", 'JPEG', 'ogle', true}, + {"image/jpeg", 'JFIF', 'ogle', true}, + {"image/x-photoshop", '8BPS', '8BIM', true}, + {"image/pict", 'PICT', 'ogle', true}, + {"image/png", 'PNGf', 'ogle', true}, + {"image/x-sgi", '.SGI', 'ogle', true}, + {"image/x-targa", 'TPIC', 'ogle', true}, + {"image/tiff", 'TIFF', 'ogle', true}, + {"text/html", 'TEXT', 'MOSS', false}, + {"text/plain", 'TEXT', 'ttxt', true}, + {"text/rtf", 'TEXT', 'MSWD', false}, + {"text/x-source-code", 'TEXT', 'R*ch', false}, + {"video/mpeg", 'MPEG', 'TVOD', true}, + {"video/quicktime", 'MooV', 'TVOD', true}, + {"video/x-flc", 'FLI ', 'TVOD', true}, + {"video/x-msvideo", 'VfW ', 'TVOD', true}, + {NULL, 0, 0, false} // End marker +}; + +void get_finder_type(const char *path, uint32 &type, uint32 &creator) +{ + type = 0; + creator = 0; + + // Open file + int fd = open(path, O_RDONLY); + if (fd < 0) + return; + + // Read BeOS MIME type and close file + char mime[256]; + ssize_t actual = fs_read_attr(fd, "BEOS:TYPE", B_MIME_STRING_TYPE, 0, mime, 256); + mime[255] = 0; + + if (actual > 0) { + + // Translate MIME type to MacOS type/creator + char mactype[4]; + if (sscanf(mime, "application/x-MacOS-%c%c%c%c", mactype, mactype+1, mactype+2, mactype+3) == 4) { + + // MacOS style type + memcpy(&type, mactype, 4); + + } else { + + // MIME string, look in table + for (int i=0; m2t_translation[i].mime; i++) { + if (!strcmp(mime, m2t_translation[i].mime)) { + type = m2t_translation[i].type; + creator = m2t_translation[i].creator; + break; + } + } + } + } + + // Override file type with MACOS:CREATOR attribute + fs_read_attr(fd, "MACOS:CREATOR", B_UINT32_TYPE, 0, &creator, 4); + + // Close file + close(fd); +} + +void set_finder_type(const char *path, uint32 type, uint32 creator) +{ + // Open file + int fd = open(path, O_WRONLY); + if (fd < 0) + return; + + // Set BEOS:TYPE attribute + if (type) { + bool written = false; + for (int i=0; m2t_translation[i].mime; i++) { + if (m2t_translation[i].type == type && m2t_translation[i].reversible) { + fs_write_attr(fd, "BEOS:TYPE", B_MIME_STRING_TYPE, 0, m2t_translation[i].mime, strlen(m2t_translation[i].mime) + 1); + written = true; + break; + } + } + if (!written) { + char mime[256]; + sprintf(mime, "application/x-MacOS-%c%c%c%c", type >> 24, type >> 16, type >> 8, type); + fs_write_attr(fd, "BEOS:TYPE", B_MIME_STRING_TYPE, 0, mime, strlen(mime) + 1); + } + } + + // Set MACOS:CREATOR attribute + if (creator) + fs_write_attr(fd, "MACOS:CREATOR", B_UINT32_TYPE, 0, &creator, 4); + + // Close file + close(fd); +} + + +/* + * Get/set finder flags for file/dir specified by full path (MACOS:HFS_FLAGS attribute) + */ + +void get_finder_flags(const char *path, uint16 &flags) +{ + flags = DEFAULT_FINDER_FLAGS; // Default + + // Open file + int fd = open(path, O_RDONLY); + if (fd < 0) + return; + + // Read MACOS:HFS_FLAGS attribute + fs_read_attr(fd, "MACOS:HFS_FLAGS", B_UINT16_TYPE, 0, &flags, 2); + + // Close file + close(fd); +} + +void set_finder_flags(const char *path, uint16 flags) +{ + // Open file + int fd = open(path, O_WRONLY); + if (fd < 0) + return; + + // Write MACOS:HFS_FLAGS attribute + if (flags != DEFAULT_FINDER_FLAGS) + fs_write_attr(fd, "MACOS:HFS_FLAGS", B_UINT16_TYPE, 0, &flags, 2); + else + fs_remove_attr(fd, "MACOS:HFS_FLAGS"); + + // Close file + close(fd); +} + + +/* + * Resource fork emulation functions + */ + +uint32 get_rfork_size(const char *path) +{ + // Open file + int fd = open(path, O_RDONLY); + if (fd < 0) + return 0; + + // Get size of MACOS:RFORK attribute + struct attr_info info; + if (fs_stat_attr(fd, "MACOS:RFORK", &info) < 0) + info.size = 0; + + // Close file and return size + close(fd); + return info.size; +} + +int open_rfork(const char *path, int flag) +{ + // Open original file + int fd = open(path, flag); + if (fd < 0) + return -1; + + // Open temporary file for resource fork + char rname[L_tmpnam]; + tmpnam(rname); + int rfd = open(rname, O_RDWR | O_CREAT | O_TRUNC, 0664); + if (rfd < 0) { + close(fd); + return -1; + } + unlink(rname); // File will be deleted when closed + + // Get size of MACOS:RFORK attribute + struct attr_info info; + if (fs_stat_attr(fd, "MACOS:RFORK", &info) < 0) + info.size = 0; + + // Copy resource data from attribute to temporary file + if (info.size > 0) { + + // Allocate buffer + void *buf = malloc(info.size); + if (buf == NULL) { + close(rfd); + close(fd); + return -1; + } + + // Copy data + fs_read_attr(fd, "MACOS:RFORK", B_RAW_TYPE, 0, buf, info.size); + write(rfd, buf, info.size); + lseek(rfd, 0, SEEK_SET); + + // Free buffer + if (buf) + free(buf); + } + + // Close original file + close(fd); + return rfd; +} + +void close_rfork(const char *path, int fd) +{ + if (fd < 0) + return; + + // Get size of temporary file + struct stat st; + if (fstat(fd, &st) < 0) + st.st_size = 0; + + // Open original file + int ofd = open(path, O_WRONLY); + if (ofd > 0) { + + // Copy resource data to MACOS:RFORK attribute + if (st.st_size > 0) { + + // Allocate buffer + void *buf = malloc(st.st_size); + if (buf == NULL) { + close(ofd); + close(fd); + return; + } + + // Copy data + lseek(fd, 0, SEEK_SET); + read(fd, buf, st.st_size); + fs_write_attr(ofd, "MACOS:RFORK", B_RAW_TYPE, 0, buf, st.st_size); + + // Free buffer + if (buf) + free(buf); + + } else + fs_remove_attr(ofd, "MACOS:RFORK"); + + // Close original file + close(ofd); + } + + // Close temporary file + close(fd); +} + + +/* + * Read "length" bytes from file to "buffer", + * returns number of bytes read (or 0) + */ + +static inline ssize_t sread(int fd, void *buf, size_t count) +{ + ssize_t res; + while ((res = read(fd, buf, count)) == B_INTERRUPTED) ; + return res; +} + +size_t extfs_read(int fd, void *buffer, size_t length) +{ + errno = 0; + + // Buffer in kernel space? + size_t actual = 0; + if ((uint32)buffer < 0x80000000) { + + // Yes, transfer via buffer + while (length) { + size_t transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length; + ssize_t res = sread(fd, tmp_buf, transfer_size); + if (res >= 0) { + memcpy(buffer, tmp_buf, res); + buffer = (void *)((uint8 *)buffer + res); + length -= res; + actual += res; + } + if (res != transfer_size) + return actual; + } + + } else { + + // No, transfer directly + actual = sread(fd, buffer, length); + if (actual < 0) + actual = 0; + } + return actual; +} + + +/* + * Write "length" bytes from "buffer" to file, + * returns number of bytes written (or 0) + */ + +static inline ssize_t swrite(int fd, void *buf, size_t count) +{ + ssize_t res; + while ((res = write(fd, buf, count)) == B_INTERRUPTED) ; + return res; +} + +size_t extfs_write(int fd, void *buffer, size_t length) +{ + errno = 0; + + // Buffer in kernel space? + size_t actual = 0; + if ((uint32)buffer < 0x80000000) { + + // Yes, transfer via buffer + while (length) { + size_t transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length; + memcpy(tmp_buf, buffer, transfer_size); + ssize_t res = swrite(fd, tmp_buf, transfer_size); + if (res >= 0) { + buffer = (void *)((uint8 *)buffer + res); + length -= res; + actual += res; + } + if (res != transfer_size) + return actual; + } + + } else { + + // No, transfer directly + actual = swrite(fd, buffer, length); + if (actual < 0) + actual = 0; + } + return actual; +} diff --git a/BasiliskII/src/BeOS/main_beos.cpp b/BasiliskII/src/BeOS/main_beos.cpp index 8629a48c..cd2c57a2 100644 --- a/BasiliskII/src/BeOS/main_beos.cpp +++ b/BasiliskII/src/BeOS/main_beos.cpp @@ -34,15 +34,7 @@ #include "cpu_emulation.h" #include "xpram.h" #include "timer.h" -#include "sony.h" -#include "disk.h" -#include "cdrom.h" -#include "scsi.h" -#include "audio.h" #include "video.h" -#include "serial.h" -#include "ether.h" -#include "clip.h" #include "rom_patches.h" #include "prefs.h" #include "prefs_editor.h" @@ -276,86 +268,8 @@ void BasiliskII::StartEmulator(void) return; } - // Check ROM version - if (!CheckROM()) { - ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR)); - PostMessage(B_QUIT_REQUESTED); - return; - } - - // Set CPU and FPU type (UAE emulation) - switch (ROMVersion) { - case ROM_VERSION_64K: - case ROM_VERSION_PLUS: - case ROM_VERSION_CLASSIC: - CPUType = 0; - FPUType = 0; - TwentyFourBitAddressing = true; - break; - case ROM_VERSION_II: - CPUType = 2; - FPUType = PrefsFindBool("fpu") ? 1 : 0; - TwentyFourBitAddressing = true; - break; - case ROM_VERSION_32: - CPUType = 3; - FPUType = PrefsFindBool("fpu") ? 1 : 0; - TwentyFourBitAddressing = false; - break; - } - CPUIs68060 = false; - - // Load XPRAM - XPRAMInit(); - - // Set boot volume - int16 i16 = PrefsFindInt16("bootdrive"); - XPRAM[0x78] = i16 >> 8; - XPRAM[0x79] = i16 & 0xff; - i16 = PrefsFindInt16("bootdriver"); - XPRAM[0x7a] = i16 >> 8; - XPRAM[0x7b] = i16 & 0xff; - - // Start XPRAM watchdog thread - xpram_thread = spawn_thread(xpram_func, "XPRAM Watchdog", B_LOW_PRIORITY, this); - resume_thread(xpram_thread); - - // Init drivers - SonyInit(); - DiskInit(); - CDROMInit(); - SCSIInit(); - - // Init network - EtherInit(); - - // Init serial ports - SerialInit(); - - // Init Time Manager - TimerInit(); - - // Init clipboard - ClipInit(); - - // Init audio - AudioInit(); - - // Init video - if (!VideoInit(ROMVersion == ROM_VERSION_64K || ROMVersion == ROM_VERSION_PLUS || ROMVersion == ROM_VERSION_CLASSIC)) { - PostMessage(B_QUIT_REQUESTED); - return; - } - - // Init 680x0 emulation (this also activates the memory system which is needed for PatchROM()) - if (!Init680x0()) { - PostMessage(B_QUIT_REQUESTED); - return; - } - - // Install ROM patches - if (!PatchROM()) { - ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR)); + // Initialize everything + if (!InitAll()) { PostMessage(B_QUIT_REQUESTED); return; } @@ -366,6 +280,10 @@ void BasiliskII::StartEmulator(void) // Disallow quitting with Alt-Q from now on AllowQuitting = false; + // Start XPRAM watchdog thread + xpram_thread = spawn_thread(xpram_func, "XPRAM Watchdog", B_LOW_PRIORITY, this); + resume_thread(xpram_thread); + // Start 60Hz interrupt tick_thread = spawn_thread(tick_func, "60Hz", B_REAL_TIME_PRIORITY, this); resume_thread(tick_thread); @@ -421,32 +339,8 @@ void BasiliskII::Quit(void) wait_for_thread(xpram_thread, &l); } - // Save XPRAM - XPRAMExit(); - - // Exit video - VideoExit(); - - // Exit audio - AudioExit(); - - // Exit clipboard - ClipExit(); - - // Exit Time Manager - TimerExit(); - - // Exit serial ports - SerialExit(); - - // Exit network - EtherExit(); - - // Exit drivers - SCSIExit(); - CDROMExit(); - DiskExit(); - SonyExit(); + // Deinitialize everything + ExitAll(); // Delete ROM area if (rom_area >= 0) diff --git a/BasiliskII/src/BeOS/prefs_beos.cpp b/BasiliskII/src/BeOS/prefs_beos.cpp index 04382323..763d459c 100644 --- a/BasiliskII/src/BeOS/prefs_beos.cpp +++ b/BasiliskII/src/BeOS/prefs_beos.cpp @@ -87,4 +87,5 @@ void SavePrefs(void) void AddPlatformPrefsDefaults(void) { + PrefsReplaceString("extfs", "/boot"); } diff --git a/BasiliskII/src/BeOS/sysdeps.h b/BasiliskII/src/BeOS/sysdeps.h index 9e33a052..fa5ebb9c 100644 --- a/BasiliskII/src/BeOS/sysdeps.h +++ b/BasiliskII/src/BeOS/sysdeps.h @@ -43,6 +43,9 @@ // Time data type for Time Manager emulation typedef bigtime_t tm_time_t; +// Offset Mac->BeOS time in seconds +#define TIME_OFFSET 0x7c25b080 + // 64 bit file offsets typedef off_t loff_t; diff --git a/BasiliskII/src/BeOS/timer_beos.cpp b/BasiliskII/src/BeOS/timer_beos.cpp index 497a8f25..1b867726 100644 --- a/BasiliskII/src/BeOS/timer_beos.cpp +++ b/BasiliskII/src/BeOS/timer_beos.cpp @@ -44,8 +44,6 @@ void Microseconds(uint32 &hi, uint32 &lo) * Return local date/time in Mac format (seconds since 1.1.1904) */ -const uint32 TIME_OFFSET = 0x7c25b080; // Offset Mac->BeOS time in seconds - uint32 TimerDateTime(void) { time_t utc_now = time(NULL); diff --git a/BasiliskII/src/BeOS/user_strings_beos.cpp b/BasiliskII/src/BeOS/user_strings_beos.cpp index 3c858fe3..ca31bb0d 100644 --- a/BasiliskII/src/BeOS/user_strings_beos.cpp +++ b/BasiliskII/src/BeOS/user_strings_beos.cpp @@ -26,6 +26,9 @@ user_string_def platform_strings[] = { // Common strings that have a platform-specific variant {STR_VOLUME_IS_MOUNTED_WARN, "The volume '%s' is mounted under BeOS. Basilisk II will try to unmount it."}, + {STR_EXTFS_CTRL, "BeOS Root"}, + {STR_EXTFS_NAME, "BeOS Directory Tree"}, + {STR_EXTFS_VOLUME_NAME, "BeOS"}, // Purely platform-specific strings {STR_NO_SHEEP_DRIVER_ERR, "Cannot open /dev/sheep: %s (%08x). Basilisk II is not properly installed."}, diff --git a/BasiliskII/src/Unix/Makefile.in b/BasiliskII/src/Unix/Makefile.in index 9f071b92..1a49827d 100644 --- a/BasiliskII/src/Unix/Makefile.in +++ b/BasiliskII/src/Unix/Makefile.in @@ -26,12 +26,12 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ -s INSTALL_DATA = @INSTALL_DATA@ ## Files -SRCS = main_unix.cpp ../prefs.cpp prefs_unix.cpp sys_unix.cpp ../rom_patches.cpp \ - ../slot_rom.cpp ../rsrc_patches.cpp ../emul_op.cpp ../macos_util.cpp \ - ../xpram.cpp xpram_unix.cpp ../timer.cpp timer_unix.cpp clip_unix.cpp \ - ../adb.cpp ../serial.cpp serial_unix.cpp ../ether.cpp ../sony.cpp \ +SRCS = ../main.cpp main_unix.cpp ../prefs.cpp prefs_unix.cpp sys_unix.cpp \ + ../rom_patches.cpp ../slot_rom.cpp ../rsrc_patches.cpp ../emul_op.cpp \ + ../macos_util.cpp ../xpram.cpp xpram_unix.cpp ../timer.cpp timer_unix.cpp \ + clip_unix.cpp ../adb.cpp ../serial.cpp serial_unix.cpp ../ether.cpp ../sony.cpp \ ../disk.cpp ../cdrom.cpp ../scsi.cpp ../video.cpp video_x.cpp ../audio.cpp \ - ../user_strings.cpp user_strings_unix.cpp \ + ../extfs.cpp extfs_unix.cpp ../user_strings.cpp user_strings_unix.cpp \ $(SYSSRCS) $(CPUSRCS) APP = BasiliskII diff --git a/BasiliskII/src/Unix/extfs_unix.cpp b/BasiliskII/src/Unix/extfs_unix.cpp new file mode 100644 index 00000000..69f7a5ba --- /dev/null +++ b/BasiliskII/src/Unix/extfs_unix.cpp @@ -0,0 +1,200 @@ +/* + * extfs_unix.cpp - MacOS file system for access native file system access, Unix specific stuff + * + * Basilisk II (C) 1997-1999 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sysdeps.h" +#include "extfs.h" +#include "extfs_defs.h" + +#define DEBUG 0 +#include "debug.h" + + +// Default Finder flags +const uint16 DEFAULT_FINDER_FLAGS = kHasBeenInited; + + +/* + * Initialization + */ + +void extfs_init(void) +{ +} + + +/* + * Deinitialization + */ + +void extfs_exit(void) +{ +} + + +/* + * Get/set finder type/creator for file specified by full path + */ + +struct ext2type { + const char *ext; + uint32 type; + uint32 creator; +}; + +static const ext2type e2t_translation[] = { + {".z", 'ZIVM', 'LZIV'}, + {".gz", 'Gzip', 'Gzip'}, + {".hqx", 'TEXT', 'SITx'}, + {".pdf", 'PDF ', 'CARO'}, + {".ps", 'TEXT', 'ttxt'}, + {".sit", 'SIT!', 'SITx'}, + {".tar", 'TARF', 'TAR '}, + {".uu", 'TEXT', 'SITx'}, + {".uue", 'TEXT', 'SITx'}, + {".zip", 'ZIP ', 'ZIP '}, + {".8svx", '8SVX', 'SNDM'}, + {".aifc", 'AIFC', 'TVOD'}, + {".aiff", 'AIFF', 'TVOD'}, + {".au", 'ULAW', 'TVOD'}, + {".mid", 'MIDI', 'TVOD'}, + {".midi", 'MIDI', 'TVOD'}, + {".mp2", 'MPG ', 'TVOD'}, + {".mp3", 'MPG ', 'TVOD'}, + {".wav", 'WAVE', 'TVOD'}, + {".bmp", 'BMPf', 'ogle'}, + {".gif", 'GIFf', 'ogle'}, + {".lbm", 'ILBM', 'GKON'}, + {".ilbm", 'ILBM', 'GKON'}, + {".jpg", 'JPEG', 'ogle'}, + {".jpeg", 'JPEG', 'ogle'}, + {".pict", 'PICT', 'ogle'}, + {".png", 'PNGf', 'ogle'}, + {".sgi", '.SGI', 'ogle'}, + {".tga", 'TPIC', 'ogle'}, + {".tif", 'TIFF', 'ogle'}, + {".tiff", 'TIFF', 'ogle'}, + {".html", 'TEXT', 'MOSS'}, + {".txt", 'TEXT', 'ttxt'}, + {".rtf", 'TEXT', 'MSWD'}, + {".c", 'TEXT', 'R*ch'}, + {".cc", 'TEXT', 'R*ch'}, + {".cpp", 'TEXT', 'R*ch'}, + {".cxx", 'TEXT', 'R*ch'}, + {".h", 'TEXT', 'R*ch'}, + {".hh", 'TEXT', 'R*ch'}, + {".hpp", 'TEXT', 'R*ch'}, + {".hxx", 'TEXT', 'R*ch'}, + {".s", 'TEXT', 'R*ch'}, + {".i", 'TEXT', 'R*ch'}, + {".mpg", 'MPEG', 'TVOD'}, + {".mpeg", 'MPEG', 'TVOD'}, + {".mov", 'MooV', 'TVOD'}, + {".fli", 'FLI ', 'TVOD'}, + {".avi", 'VfW ', 'TVOD'}, + {NULL, 0, 0} // End marker +}; + +void get_finder_type(const char *path, uint32 &type, uint32 &creator) +{ + type = 0; + creator = 0; + + // Translate file name extension to MacOS type/creator + int path_len = strlen(path); + for (int i=0; e2t_translation[i].ext; i++) { + int ext_len = strlen(e2t_translation[i].ext); + if (path_len < ext_len) + continue; + if (!strcmp(path + path_len - ext_len, e2t_translation[i].ext)) { + type = e2t_translation[i].type; + creator = e2t_translation[i].creator; + break; + } + } +} + +void set_finder_type(const char *path, uint32 type, uint32 creator) +{ +} + + +/* + * Get/set finder flags for file/dir specified by full path (MACOS:HFS_FLAGS attribute) + */ + +void get_finder_flags(const char *path, uint16 &flags) +{ + flags = DEFAULT_FINDER_FLAGS; // Default +} + +void set_finder_flags(const char *path, uint16 flags) +{ +} + + +/* + * Resource fork emulation functions + */ + +uint32 get_rfork_size(const char *path) +{ + return 0; +} + +int open_rfork(const char *path, int flag) +{ + return -1; +} + +void close_rfork(const char *path, int fd) +{ +} + + +/* + * Read "length" bytes from file to "buffer", + * returns number of bytes read (or 0) + */ + +size_t extfs_read(int fd, void *buffer, size_t length) +{ + errno = 0; + return read(fd, buffer, length); +} + + +/* + * Write "length" bytes from "buffer" to file, + * returns number of bytes written (or 0) + */ + +size_t extfs_write(int fd, void *buffer, size_t length) +{ + errno = 0; + return write(fd, buffer, length); +} diff --git a/BasiliskII/src/Unix/main_unix.cpp b/BasiliskII/src/Unix/main_unix.cpp index c5542ac9..dba4a99a 100644 --- a/BasiliskII/src/Unix/main_unix.cpp +++ b/BasiliskII/src/Unix/main_unix.cpp @@ -27,18 +27,10 @@ #include "cpu_emulation.h" #include "sys.h" +#include "rom_patches.h" #include "xpram.h" #include "timer.h" -#include "sony.h" -#include "disk.h" -#include "cdrom.h" -#include "scsi.h" -#include "audio.h" #include "video.h" -#include "serial.h" -#include "ether.h" -#include "clip.h" -#include "rom_patches.h" #include "prefs.h" #include "prefs_editor.h" #include "macos_util.h" @@ -46,7 +38,7 @@ #include "version.h" #include "main.h" -#define DEBUG 1 +#define DEBUG 0 #include "debug.h" @@ -207,83 +199,13 @@ int main(int argc, char **argv) QuitEmulator(); } - // Check ROM version - if (!CheckROM()) { - ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR)); + // Initialize everything + if (!InitAll()) QuitEmulator(); - } - - // Set CPU and FPU type (UAE emulation) - switch (ROMVersion) { - case ROM_VERSION_64K: - case ROM_VERSION_PLUS: - case ROM_VERSION_CLASSIC: - CPUType = 0; - FPUType = 0; - TwentyFourBitAddressing = true; - break; - case ROM_VERSION_II: - CPUType = 2; - FPUType = PrefsFindBool("fpu") ? 1 : 0; - TwentyFourBitAddressing = true; - break; - case ROM_VERSION_32: - CPUType = 3; - FPUType = PrefsFindBool("fpu") ? 1 : 0; - TwentyFourBitAddressing = false; - break; - } - CPUIs68060 = false; - - // Load XPRAM - XPRAMInit(); - - // Set boot volume - int16 i16 = PrefsFindInt16("bootdrive"); - XPRAM[0x78] = i16 >> 8; - XPRAM[0x79] = i16 & 0xff; - i16 = PrefsFindInt16("bootdriver"); - XPRAM[0x7a] = i16 >> 8; - XPRAM[0x7b] = i16 & 0xff; // Start XPRAM watchdog thread xpram_thread_active = (pthread_create(&xpram_thread, NULL, xpram_func, NULL) == 0); - // Init drivers - SonyInit(); - DiskInit(); - CDROMInit(); - SCSIInit(); - - // Init serial ports - SerialInit(); - - // Init network - EtherInit(); - - // Init Time Manager - TimerInit(); - - // Init clipboard - ClipInit(); - - // Init audio - AudioInit(); - - // Init video - if (!VideoInit(ROMVersion == ROM_VERSION_64K || ROMVersion == ROM_VERSION_PLUS || ROMVersion == ROM_VERSION_CLASSIC)) - QuitEmulator(); - - // Init 680x0 emulation (this also activates the memory system which is needed for PatchROM()) - if (!Init680x0()) - QuitEmulator(); - - // Install ROM patches - if (!PatchROM()) { - ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR)); - QuitEmulator(); - } - #if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS) // Start 60Hz timer sigemptyset(&timer_sa.sa_mask); @@ -370,32 +292,8 @@ void QuitEmulator(void) pthread_join(xpram_thread, NULL); } - // Save XPRAM - XPRAMExit(); - - // Exit video - VideoExit(); - - // Exit audio - AudioExit(); - - // Exit clipboard - ClipExit(); - - // Exit Time Manager - TimerExit(); - - // Exit serial ports - SerialExit(); - - // Exit network - EtherExit(); - - // Exit drivers - SCSIExit(); - CDROMExit(); - DiskExit(); - SonyExit(); + // Deinitialize everything + ExitAll(); // Delete ROM area delete[] ROMBaseHost; diff --git a/BasiliskII/src/Unix/prefs_editor_gtk.cpp b/BasiliskII/src/Unix/prefs_editor_gtk.cpp index 27bd44c9..3a58c2b7 100644 --- a/BasiliskII/src/Unix/prefs_editor_gtk.cpp +++ b/BasiliskII/src/Unix/prefs_editor_gtk.cpp @@ -318,7 +318,7 @@ bool PrefsEditor(void) * "Volumes" pane */ -static GtkWidget *volume_list; +static GtkWidget *volume_list, *w_extfs; static int selected_volume; // Volume in list selected @@ -420,6 +420,8 @@ static void read_volumes_settings(void) gtk_clist_get_text(GTK_CLIST(volume_list), i, 0, &str); PrefsAddString("disk", str); } + + PrefsReplaceString("extfs", gtk_entry_get_text(GTK_ENTRY(w_extfs))); } // Create "Volumes" pane @@ -455,6 +457,8 @@ static void create_volumes_pane(GtkWidget *top) make_button_box(box, 0, buttons); make_separator(box); + w_extfs = make_entry(box, STR_EXTFS_CTRL, "extfs"); + static const opt_desc options[] = { {STR_BOOT_ANY_LAB, GTK_SIGNAL_FUNC(mn_boot_any)}, {STR_BOOT_CDROM_LAB, GTK_SIGNAL_FUNC(mn_boot_cdrom)}, diff --git a/BasiliskII/src/Unix/prefs_unix.cpp b/BasiliskII/src/Unix/prefs_unix.cpp index 606e24fc..0bb96bc0 100644 --- a/BasiliskII/src/Unix/prefs_unix.cpp +++ b/BasiliskII/src/Unix/prefs_unix.cpp @@ -92,4 +92,5 @@ void SavePrefs(void) void AddPlatformPrefsDefaults(void) { PrefsAddBool("keycodes", false); + PrefsReplaceString("extfs", "/"); } diff --git a/BasiliskII/src/Unix/sysdeps.h b/BasiliskII/src/Unix/sysdeps.h index bb31fb26..c5396123 100644 --- a/BasiliskII/src/Unix/sysdeps.h +++ b/BasiliskII/src/Unix/sysdeps.h @@ -107,6 +107,9 @@ typedef struct timespec tm_time_t; typedef struct timeval tm_time_t; #endif +/* Offset Mac->Unix time in seconds */ +#define TIME_OFFSET 0x7c25b080 + /* UAE CPU data types */ #define uae_s8 int8 #define uae_u8 uint8 diff --git a/BasiliskII/src/Unix/timer_unix.cpp b/BasiliskII/src/Unix/timer_unix.cpp index bbea5e1d..5d5947d3 100644 --- a/BasiliskII/src/Unix/timer_unix.cpp +++ b/BasiliskII/src/Unix/timer_unix.cpp @@ -50,8 +50,6 @@ void Microseconds(uint32 &hi, uint32 &lo) * Return local date/time in Mac format (seconds since 1.1.1904) */ -const uint32 TIME_OFFSET = 0x7c25b080; // Offset Mac->Unix time in seconds - uint32 TimerDateTime(void) { time_t utc_now = time(NULL); diff --git a/BasiliskII/src/Unix/user_strings_unix.cpp b/BasiliskII/src/Unix/user_strings_unix.cpp index 49e6f011..ebfc11f2 100644 --- a/BasiliskII/src/Unix/user_strings_unix.cpp +++ b/BasiliskII/src/Unix/user_strings_unix.cpp @@ -26,6 +26,9 @@ user_string_def platform_strings[] = { // Common strings that have a platform-specific variant {STR_VOLUME_IS_MOUNTED_WARN, "The volume '%s' is mounted under Unix. Basilisk II will try to unmount it."}, + {STR_EXTFS_CTRL, "Unix Root"}, + {STR_EXTFS_NAME, "Unix Directory Tree"}, + {STR_EXTFS_VOLUME_NAME, "Unix"}, // Purely platform-specific strings {STR_NO_XSERVER_ERR, "Cannot connect to X server '%s'."}, diff --git a/BasiliskII/src/emul_op.cpp b/BasiliskII/src/emul_op.cpp index 31c41071..5c22647e 100644 --- a/BasiliskII/src/emul_op.cpp +++ b/BasiliskII/src/emul_op.cpp @@ -39,6 +39,7 @@ #include "video.h" #include "audio.h" #include "ether.h" +#include "extfs.h" #include "emul_op.h" #define DEBUG 0 @@ -492,6 +493,14 @@ void EmulOp(uint16 opcode, M68kRegisters *r) r->d[0] = AudioDispatch(r->a[3], r->a[4]); break; + case M68K_EMUL_OP_EXTFS_COMM: // External file system routines + WriteMacInt16(r->a[7] + 14, ExtFSComm(ReadMacInt16(r->a[7] + 12), ReadMacInt32(r->a[7] + 8), ReadMacInt32(r->a[7] + 4))); + break; + + case M68K_EMUL_OP_EXTFS_HFS: + WriteMacInt16(r->a[7] + 20, ExtFSHFS(ReadMacInt32(r->a[7] + 16), ReadMacInt16(r->a[7] + 14), ReadMacInt32(r->a[7] + 10), ReadMacInt32(r->a[7] + 6), ReadMacInt16(r->a[7] + 4))); + break; + default: printf("FATAL: EMUL_OP called with bogus opcode %08x\n", opcode); printf("d0 %08lx d1 %08lx d2 %08lx d3 %08lx\n" diff --git a/BasiliskII/src/extfs.cpp b/BasiliskII/src/extfs.cpp new file mode 100644 index 00000000..bfb8a8a9 --- /dev/null +++ b/BasiliskII/src/extfs.cpp @@ -0,0 +1,2166 @@ +/* + * extfs.cpp - MacOS file system for access native file system access + * + * Basilisk II (C) 1997-1999 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 + */ + +/* +TODO: +LockRng +UnlockRng +(CatSearch) +(MakeFSSpec) +(GetVolMountInfoSize) +(GetVolMountInfo) +(GetForeignPrivs) +(SetForeignPrivs) +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "sysdeps.h" +#include "cpu_emulation.h" +#include "macos_util.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" + +#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) + 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(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 = 'ba'; +const uint32 MY_MEDIA_TYPE = 'basi'; + +// 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; + +// 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[32]; // Object name (C string) + 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 + + +/* + * 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; +} + + +/* + * 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 + 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; + strncpy(p->name, name, 31); + p->name[31] = 0; + p->mtime = 0; + return p; +} + + +/* + * Get full path (->full_path) for given FSItem + */ + +const int MAX_PATH_LENGTH = 1024; +static char full_path[MAX_PATH_LENGTH]; + +static void add_path_component(const char *s) +{ + int l = strlen(full_path); + if (l < MAX_PATH_LENGTH-1 && full_path[l-1] != '/') { + full_path[l] = '/'; + full_path[l+1] = 0; + } + strncat(full_path, s, MAX_PATH_LENGTH-1); +} + +static void get_path_for_fsitem(FSItem *p) +{ + 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_component(p->name); + } +} + + +/* + * 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++ = strlen(src); + char c; + while ((c = *src++) != 0) { + if (c == ':') + c = '/'; + *dst++ = c; + } +} + +// Convert pascal string to C string +static void pstr2cstr(char *dst, const char *src) +{ + int size = *src++; + while (size--) { + char c = *src++; + if (c == '/') + c = ':'; + *dst++ = c; + } + *dst = 0; +} + +// 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++; + 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 FSItem + FSItem *p = new FSItem; + first_fs_item = last_fs_item = p; + p->next = NULL; + p->id = ROOT_ID; + p->parent_id = ROOT_PARENT_ID; + p->parent = NULL; + strncpy(p->name, GetString(STR_EXTFS_VOLUME_NAME), 32); + + // 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; + 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 %ld, %08lx\n", r.d[0], r.a[0])); + if ((r.d[0] & 0xffff) || !(r.a[0] & (1 << gestaltHasFileSystemManager))) + return; + + // Yes, version >=1.2? + r.d[0] = gestaltFSMVersion; + Execute68kTrap(0xa1ad, &r); // Gestalt() + D(bug("FSMVersion %ld, %08lx\n", r.d[0], r.a[0])); + if ((r.d[0] & 0xffff) || (r.a[0] < 0x0120)) + 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_EXEC_RETURN); 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_EXEC_RETURN); 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_EXEC_RETURN); p+= 2; + if (p - fs_data != fsResolveWDCB) + goto fsdat_error; + WriteMacInt16(p, 0x4267); p+= 2; // clr.w -(sp) + WriteMacInt16(p, 0x42a7); p+= 2; // clr.l -(sp) + 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, 0x700e); p+= 2; // UTResolveWDCB + WriteMacInt16(p, 0xa824); p+= 2; // FSMgr + WriteMacInt16(p, 0x301f); p+= 2; // move.w (sp)+,d0 + WriteMacInt16(p, M68K_EXEC_RETURN); 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_EXEC_RETURN); 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_EXEC_RETURN); 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_EXEC_RETURN); 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_EXEC_RETURN); 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_EXEC_RETURN); 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_EXEC_RETURN); 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_EXEC_RETURN); 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_EXEC_RETURN); 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_EXEC_RETURN); 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_EXEC_RETURN); 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_EXEC_RETURN); 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_EXEC_RETURN); 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_EXEC_RETURN); 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); + memcpy(Mac2HostAddr(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)) { + memcpy(Mac2HostAddr(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 (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\n")); + 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); + int16 more_matches = ReadMacInt16(fs_data + fsReturn + 2); + int16 vRefNum = ReadMacInt16(fs_data + fsReturn + 4); + uint32 vcb = ReadMacInt32(fs_data + fsReturn + 6); +// D(bug(" UTDetermineVol() returned %d, status %d\n", r.d[0], status)); + result = 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] = 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 = 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 = 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 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; + 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 = 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(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(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 (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); + uint16 sysVCBLength = ReadMacInt16(fs_data + fsReturn); + 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 r.d[0]; + + // Init VCB + WriteMacInt16(vcb + vcbSigWord, 0x4244); +#ifdef __BEOS__ + WriteMacInt32(vcb + vcbCrDate, root_stat.st_crtime + TIME_OFFSET); +#else + WriteMacInt32(vcb + vcbCrDate, 0); +#endif + WriteMacInt32(vcb + vcbLsMod, root_stat.st_mtime + TIME_OFFSET); + WriteMacInt32(vcb + vcbVolBkUp, 0); + WriteMacInt16(vcb + vcbNmFls, 1); //!! + WriteMacInt16(vcb + vcbNmRtDirs, 1); //!! + WriteMacInt16(vcb + vcbNmAlBlks, 0xffff); //!! + WriteMacInt32(vcb + vcbAlBlkSiz, 1024); + WriteMacInt32(vcb + vcbClpSiz, 1024); + WriteMacInt32(vcb + vcbNxtCNID, next_cnid); + WriteMacInt16(vcb + vcbFreeBks, 0xffff); //!! + memcpy(Mac2HostAddr(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 = ReadMacInt32(fs_data + fsReturn); + D(bug(" UTAddNewVCB() returned %d, vRefNum %d\n", r.d[0], vRefNum)); + if (r.d[0] & 0xffff) + return 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 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); +#ifdef __BEOS__ + WriteMacInt32(pb + ioVCrDate, root_stat.st_crtime + TIME_OFFSET); +#else + WriteMacInt32(pb + ioVCrDate, 0); +#endif + WriteMacInt32(pb + ioVLsMod, root_stat.st_mtime + TIME_OFFSET); + WriteMacInt16(pb + ioVAtrb, 0); + WriteMacInt16(pb + ioVNmFls, 1); //!! + WriteMacInt16(pb + ioVBitMap, 0); + WriteMacInt16(pb + ioAllocPtr, 0); + WriteMacInt16(pb + ioVNmAlBlks, 0xffff); //!! + WriteMacInt32(pb + ioVAlBlkSiz, 1024); + WriteMacInt32(pb + ioVClpSiz, 1024); + 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); //!! + memset(Mac2HostAddr(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 + uint8 vol[SIZEOF_GetVolParmsInfoBuffer]; + WriteMacInt16((uint32)vol + vMVersion, 2); + WriteMacInt32((uint32)vol + vMAttrib, kNoMiniFndr | kNoVNEdit | kNoLclSync | kTrshOffLine | kNoSwitchTo | kNoBootBlks | kNoSysDir | kHasExtFSVol); + WriteMacInt32((uint32)vol + vMLocalHand, 0); + WriteMacInt32((uint32)vol + vMServerAdr, 0); + WriteMacInt32((uint32)vol + vMVolumeGrade, 0); + WriteMacInt16((uint32)vol + vMForeignPrivID, 0); + uint32 actual = ReadMacInt32(pb + ioReqCount); + if (actual > sizeof(vol)) + actual = sizeof(vol); + memcpy(Mac2HostAddr(ReadMacInt32(pb + ioBuffer)), vol, actual); + WriteMacInt32(pb + ioActCount, actual); + 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 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 %#s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), 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 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 %#s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), 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; id_name[0] == '.') + goto read_next_de; // Suppress name beginning with '.' (MacOS could interpret these as driver names) + //!! suppress directories + } + add_path_component(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->name); + WriteMacInt16(pb + ioFRefNum, 0); + WriteMacInt8(pb + ioFlAttrib, access(full_path, W_OK) == 0 ? 0 : faLocked); + WriteMacInt32(pb + ioDirID, fs_item->id); + +#ifdef __BEOS__ + WriteMacInt32(pb + ioFlCrDat, st.st_crtime + TIME_OFFSET); +#else + WriteMacInt32(pb + ioFlCrDat, 0); +#endif + WriteMacInt32(pb + ioFlMdDat, st.st_mtime + TIME_OFFSET); + + memset(Mac2HostAddr(pb + ioFlFndrInfo), 0, SIZEOF_FInfo); + uint32 type, creator; // pb may point to kernel space, but stack is switched + get_finder_type(full_path, type, creator); + WriteMacInt32(pb + ioFlFndrInfo + fdType, type); + WriteMacInt32(pb + ioFlFndrInfo + fdCreator, creator); + uint16 fflags; + get_finder_flags(full_path, fflags); + WriteMacInt16(pb + ioFlFndrInfo + fdFlags, fflags); + + WriteMacInt16(pb + ioFlStBlk, 0); + WriteMacInt32(pb + ioFlLgLen, st.st_size); + WriteMacInt32(pb + ioFlPyLen, (st.st_size + 1023) & ~1023); + WriteMacInt16(pb + ioFlRStBlk, 0); + uint32 rf_size = get_rfork_size(full_path); + WriteMacInt32(pb + ioFlRLgLen, rf_size); + WriteMacInt32(pb + ioFlRPyLen, (rf_size + 1023) & ~1023); + + if (hfs) { + WriteMacInt32(pb + ioFlBkDat, 0); + memset(Mac2HostAddr(pb + ioFlXFndrInfo), 0, SIZEOF_FXInfo); + 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 %#s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), 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 attributes + set_finder_type(full_path, ReadMacInt32(pb + ioFlFndrInfo + fdType), ReadMacInt32(pb + ioFlFndrInfo + fdCreator)); + set_finder_flags(full_path, ReadMacInt16(pb + ioFlFndrInfo + fdFlags)); + //!! 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 %#s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), ReadMacInt16(pb + ioFDirIndex), ReadMacInt32(pb + ioDirID))); + + FSItem *fs_item; + int16 dir_index = ReadMacInt16(pb + ioFDirIndex); + if (dir_index == -1) { // 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; id_name[0] == '.') + goto read_next_de; // Suppress name beginning with '.' (MacOS could interpret these as driver names) + } + add_path_component(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->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); +#ifdef __BEOS__ + WriteMacInt32(pb + ioFlCrDat, st.st_crtime + TIME_OFFSET); +#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, mtime); + WriteMacInt32(pb + ioFlBkDat, 0); + if (S_ISDIR(st.st_mode)) { + memset(Mac2HostAddr(pb + ioDrUsrWds), 0, SIZEOF_DInfo); + memset(Mac2HostAddr(pb + ioDrFndrInfo), 0, SIZEOF_DXInfo); + uint16 fflags; // pb may point to kernel space, but stack is switched + get_finder_flags(full_path, fflags); + WriteMacInt16(pb + ioDrUsrWds + frFlags, fflags); + + // 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; + count++; + } + closedir(d); + } + fs_item->cache_dircount = count; + } + WriteMacInt16(pb + ioDrNmFls, count); + } else { + memset(Mac2HostAddr(pb + ioFlFndrInfo), 0, SIZEOF_FInfo); + memset(Mac2HostAddr(pb + ioFlXFndrInfo), 0, SIZEOF_FXInfo); + uint32 type, creator; // pb may point to kernel space, but stack is switched + get_finder_type(full_path, type, creator); + WriteMacInt32(pb + ioFlFndrInfo + fdType, type); + WriteMacInt32(pb + ioFlFndrInfo + fdCreator, creator); + uint16 fflags; + get_finder_flags(full_path, fflags); + WriteMacInt16(pb + ioFlFndrInfo + fdFlags, fflags); + WriteMacInt16(pb + ioFlStBlk, 0); + WriteMacInt32(pb + ioFlLgLen, st.st_size); + WriteMacInt32(pb + ioFlPyLen, (st.st_size + 1023) & ~1023); + WriteMacInt16(pb + ioFlRStBlk, 0); + uint32 rf_size = get_rfork_size(full_path); + WriteMacInt32(pb + ioFlRLgLen, rf_size); + WriteMacInt32(pb + ioFlRPyLen, (rf_size + 1023) & ~1023); + 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 %#s, idx %d, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), 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 attributes + if (S_ISDIR(st.st_mode)) + set_finder_flags(full_path, ReadMacInt16(pb + ioDrUsrWds + frFlags)); + else { + set_finder_type(full_path, ReadMacInt32(pb + ioFlFndrInfo + fdType), ReadMacInt32(pb + ioFlFndrInfo + fdCreator)); + set_finder_flags(full_path, ReadMacInt16(pb + ioFlFndrInfo + fdFlags)); + } + //!! 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 %#s, dirID %d, perm %d\n", pb, resource_fork ? "rsrc" : "data", ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), 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) + 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) + 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 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 + 1023) & ~1023); + WriteMacInt32(fcb + fcbCrPs, 0); + WriteMacInt32(fcb + fcbVPtr, vcb); + WriteMacInt32(fcb + fcbClmpSize, 1024); + uint32 type, creator; // fcb may point to kernel space, but stack is switched + get_finder_type(full_path, type, creator); + WriteMacInt32(fcb + fcbFType, type); + WriteMacInt32(fcb + fcbCatPos, fd); + WriteMacInt32(fcb + fcbDirID, fs_item->parent_id); + cstr2pstr((char *)Mac2HostAddr(fcb + fcbCName), fs_item->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 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; iid); + return noErr; + } +} + +// Delete file/directory +static int16 fs_delete(uint32 pb, uint32 dirID) +{ + D(bug(" fs_delete(%08lx), vRefNum %d, name %#s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), 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 (remove(full_path) < 0) { + int16 err = errno2oserr(); + if (errno == EISDIR) { // Workaround for BeOS bug + if (rmdir(full_path) < 0) + return errno2oserr(); + else + return noErr; + } else + return err; + } else + return noErr; +} + +// Rename file/directory +static int16 fs_rename(uint32 pb, uint32 dirID) +{ + D(bug(" fs_rename(%08lx), vRefNum %d, name %#s, dirID %d, new name %#s\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), dirID, Mac2HostAddr(ReadMacInt32(pb + ioMisc)))); + + // 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 + uint8 new_pb[SIZEOF_IOParam]; + memcpy(new_pb, Mac2HostAddr(pb), SIZEOF_IOParam); + WriteMacInt32((uint32)new_pb + ioNamePtr, ReadMacInt32(pb + ioMisc)); + FSItem *new_item; + result = get_item_and_path((uint32)new_pb, 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 (rename(old_path, full_path) < 0) + return errno2oserr(); + else { + // The ID of the old file/dir has to stay the same, so we swap the IDs of the FSItems + 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 %#s, dirID %d, new name %#s, new dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), ReadMacInt32(pb + ioDirID), Mac2HostAddr(ReadMacInt32(pb + ioNewName)), 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 + uint8 new_pb[SIZEOF_IOParam]; + memcpy(new_pb, Mac2HostAddr(pb), SIZEOF_IOParam); + WriteMacInt32((uint32)new_pb + ioNamePtr, ReadMacInt32(pb + ioNewName)); + FSItem *new_dir_item; + result = get_item_and_path((uint32)new_pb, ReadMacInt32(pb + ioNewDirID), new_dir_item); + if (result != noErr) + return result; + + // Append old file/dir name + add_path_component(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 (rename(old_path, full_path) < 0) + 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) { + 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 %#s, dirID %d\n", pb, ReadMacInt16(pb + ioVRefNum), Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), 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\n", r.d[0])); + return 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 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)) + memcpy(Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), Mac2HostAddr(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 r.d[0]; + + // Return information + WriteMacInt16(pb + ioWDProcID, ReadMacInt32(wdcb + wdProcID)); + WriteMacInt16(pb + ioWDVRefNum, ReadMacInt16(ReadMacInt32(wdcb + wdVCBPtr) + vcbVRefNum)); + if (ReadMacInt32(pb + ioNamePtr)) + memcpy(Mac2HostAddr(ReadMacInt32(pb + ioNamePtr)), Mac2HostAddr(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; + 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; + } +} diff --git a/BasiliskII/src/include/emul_op.h b/BasiliskII/src/include/emul_op.h index f09cfb2e..b24a7203 100644 --- a/BasiliskII/src/include/emul_op.h +++ b/BasiliskII/src/include/emul_op.h @@ -79,6 +79,8 @@ enum { M68K_EMUL_OP_PUT_SCRAP, M68K_EMUL_OP_CHECKLOAD, M68K_EMUL_OP_AUDIO, + M68K_EMUL_OP_EXTFS_COMM, + M68K_EMUL_OP_EXTFS_HFS, M68K_EMUL_OP_MAX // highest number }; diff --git a/BasiliskII/src/include/extfs.h b/BasiliskII/src/include/extfs.h new file mode 100644 index 00000000..d9761994 --- /dev/null +++ b/BasiliskII/src/include/extfs.h @@ -0,0 +1,45 @@ +/* + * extfs.h - MacOS file system for access native file system access + * + * Basilisk II (C) 1997-1999 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 + */ + +#ifndef EXTFS_H +#define EXTFS_H + +extern void ExtFSInit(void); +extern void ExtFSExit(void); + +extern void InstallExtFS(void); + +extern int16 ExtFSComm(uint16 message, uint32 paramBlock, uint32 globalsPtr); +extern int16 ExtFSHFS(uint32 vcb, uint16 selectCode, uint32 paramBlock, uint32 globalsPtr, int16 fsid); + +// System specific and internal functions/data +extern void extfs_init(void); +extern void extfs_exit(void); +extern void get_finder_type(const char *path, uint32 &type, uint32 &creator); +extern void set_finder_type(const char *path, uint32 type, uint32 creator); +extern void get_finder_flags(const char *path, uint16 &flags); +extern void set_finder_flags(const char *path, uint16 flags); +extern uint32 get_rfork_size(const char *path); +extern int open_rfork(const char *path, int flag); +extern void close_rfork(const char *path, int fd); +extern size_t extfs_read(int fd, void *buffer, size_t length); +extern size_t extfs_write(int fd, void *buffer, size_t length); + +#endif diff --git a/BasiliskII/src/include/extfs_defs.h b/BasiliskII/src/include/extfs_defs.h new file mode 100644 index 00000000..5f6ecbde --- /dev/null +++ b/BasiliskII/src/include/extfs_defs.h @@ -0,0 +1,559 @@ +/* + * extfs_defs.h - MacOS types and structures for external file system + * + * Basilisk II (C) 1997-1999 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 + */ + +#ifndef EXTFS_DEFS_H +#define EXTFS_DEFS_H + +#include "macos_util.h" + +// Gestalt selectors +enum { + gestaltFSAttr = 'fs ', + gestaltFullExtFSDispatching = 0, + gestaltHasFSSpecCalls = 1, + gestaltHasFileSystemManager = 2, + gestaltFSMDoesDynamicLoad = 3, + gestaltFSSupports4GBVols = 4, + gestaltFSSupports2TBVols = 5, + gestaltHasExtendedDiskInit = 6, + gestaltDTMgrSupportsFSM = 7 +}; + +enum { + gestaltFSMVersion = 'fsm ' +}; + +// File attributes +enum { + faLocked = 0x01, + faRFOpen = 0x04, + faDFOpen = 0x08, + faIsDir = 0x10, + faOpen = 0x80 +}; + +// Volume attributes +enum { + vaBusy = 0x40, + vaHardLock = 0x80, + vaSoftLock = 0x8000 +}; + +// vMAttrib (GetVolParms) constants +enum { + kLimitFCBs = 1 << 31, + kLocalWList = 1 << 30, + kNoMiniFndr = 1 << 29, + kNoVNEdit = 1 << 28, + kNoLclSync = 1 << 27, + kTrshOffLine = 1 << 26, + kNoSwitchTo = 1 << 25, + kNoDeskItems = 1 << 20, + kNoBootBlks = 1 << 19, + kAccessCntl = 1 << 18, + kNoSysDir = 1 << 17, + kHasExtFSVol = 1 << 16, + kHasOpenDeny = 1 << 15, + kHasCopyFile = 1 << 14, + kHasMoveRename = 1 << 13, + kHasDesktopMgr = 1 << 12, + kHasShortName = 1 << 11, + kHasFolderLock = 1 << 10, + kHasPersonalAccessPrivileges = 1 << 9, + kHasUserGroupList = 1 << 8, + kHasCatSearch = 1 << 7, + kHasFileIDs = 1 << 6, + kHasBTreeMgr = 1 << 5, + kHasBlankAccessPrivileges = 1 << 4, + kSupportsAsyncRequests = 1 << 3 +}; + +enum { + fsUsrCNID = 16, + kHFSBit = 9, + kHFSMask = 0x0200, + kAsyncBit = 10, + kAsyncMask = 0x0400 +}; + +// HFSCIProc selectCode values +enum { + kFSMOpen = 0xA000, + kFSMClose = 0xA001, + kFSMRead = 0xA002, + kFSMWrite = 0xA003, + kFSMGetVolInfo = 0xA007, + kFSMCreate = 0xA008, + kFSMDelete = 0xA009, + kFSMOpenRF = 0xA00A, + kFSMRename = 0xA00B, + kFSMGetFileInfo = 0xA00C, + kFSMSetFileInfo = 0xA00D, + kFSMUnmountVol = 0xA00E, + kFSMMountVol = 0xA00F, + kFSMAllocate = 0xA010, + kFSMGetEOF = 0xA011, + kFSMSetEOF = 0xA012, + kFSMFlushVol = 0xA013, + kFSMGetVol = 0xA014, + kFSMSetVol = 0xA015, + kFSMEject = 0xA017, + kFSMGetFPos = 0xA018, + kFSMOffline = 0xA035, + kFSMSetFilLock = 0xA041, + kFSMRstFilLock = 0xA042, + kFSMSetFilType = 0xA043, + kFSMSetFPos = 0xA044, + kFSMFlushFile = 0xA045, + kFSMOpenWD = 0x0001, + kFSMCloseWD = 0x0002, + kFSMCatMove = 0x0005, + kFSMDirCreate = 0x0006, + kFSMGetWDInfo = 0x0007, + kFSMGetFCBInfo = 0x0008, + kFSMGetCatInfo = 0x0009, + kFSMSetCatInfo = 0x000A, + kFSMSetVolInfo = 0x000B, + kFSMLockRng = 0x0010, + kFSMUnlockRng = 0x0011, + kFSMXGetVolInfo = 0x0012, + kFSMCreateFileIDRef = 0x0014, + kFSMDeleteFileIDRef = 0x0015, + kFSMResolveFileIDRef = 0x0016, + kFSMExchangeFiles = 0x0017, + kFSMCatSearch = 0x0018, + kFSMOpenDF = 0x001A, + kFSMMakeFSSpec = 0x001B, + kFSMDTGetPath = 0x0020, + kFSMDTCloseDown = 0x0021, + kFSMDTAddIcon = 0x0022, + kFSMDTGetIcon = 0x0023, + kFSMDTGetIconInfo = 0x0024, + kFSMDTAddAPPL = 0x0025, + kFSMDTRemoveAPPL = 0x0026, + kFSMDTGetAPPL = 0x0027, + kFSMDTSetComment = 0x0028, + kFSMDTRemoveComment = 0x0029, + kFSMDTGetComment = 0x002A, + kFSMDTFlush = 0x002B, + kFSMDTReset = 0x002C, + kFSMDTGetInfo = 0x002D, + kFSMDTOpenInform = 0x002E, + kFSMDTDelete = 0x002F, + kFSMGetVolParms = 0x0030, + kFSMGetLogInInfo = 0x0031, + kFSMGetDirAccess = 0x0032, + kFSMSetDirAccess = 0x0033, + kFSMMapID = 0x0034, + kFSMMapName = 0x0035, + kFSMCopyFile = 0x0036, + kFSMMoveRename = 0x0037, + kFSMOpenDeny = 0x0038, + kFSMOpenRFDeny = 0x0039, + kFSMGetXCatInfo = 0x003A, + kFSMGetVolMountInfoSize = 0x003F, + kFSMGetVolMountInfo = 0x0040, + kFSMVolumeMount = 0x0041, + kFSMShare = 0x0042, + kFSMUnShare = 0x0043, + kFSMGetUGEntry = 0x0044, + kFSMGetForeignPrivs = 0x0060, + kFSMSetForeignPrivs = 0x0061 +}; + +// UTDetermineVol status values +enum { + dtmvError = 0, + dtmvFullPathname = 1, + dtmvVRefNum = 2, + dtmvWDRefNum = 3, + dtmvDriveNum = 4, + dtmvDefault = 5 +}; + +// Miscellaneous constants used by FSM +enum { + fsdVersion1 = 1, + fsmIgnoreFSID = 0xFFFE, + fsmGenericFSID = 0xFFFF +}; + +// compInterfMask bits common to all FSM components +enum { + fsmComponentEnableBit = 31, + fsmComponentEnableMask = (long)0x80000000, + fsmComponentBusyBit = 30, + fsmComponentBusyMask = 0x40000000 +}; + +// compInterfMask bits specific to HFS component +enum { + hfsCIDoesHFSBit = 23, + hfsCIDoesHFSMask = 0x00800000, + hfsCIDoesAppleShareBit = 22, + hfsCIDoesAppleShareMask = 0x00400000, + hfsCIDoesDeskTopBit = 21, + hfsCIDoesDeskTopMask = 0x00200000, + hfsCIDoesDynamicLoadBit = 20, + hfsCIDoesDynamicLoadMask = 0x00100000, + hfsCIResourceLoadedBit = 19, + hfsCIResourceLoadedMask = 0x00080000, + hfsCIHasHLL2PProcBit = 18, + hfsCIHasHLL2PProcMask = 0x00040000, + hfsCIWantsDTSupportBit = 17, + hfsCIWantsDTSupportMask = 0x00020000 +}; + +// FCBRec.fcbFlags bits +enum { + fcbWriteBit = 0, + fcbWriteMask = 0x01, + fcbResourceBit = 1, + fcbResourceMask = 0x02, + fcbWriteLockedBit = 2, + fcbWriteLockedMask = 0x04, + fcbSharedWriteBit = 4, + fcbSharedWriteMask = 0x10, + fcbFileLockedBit = 5, + fcbFileLockedMask = 0x20, + fcbOwnClumpBit = 6, + fcbOwnClumpMask = 0x40, + fcbModifiedBit = 7, + fcbModifiedMask = 0x80 +}; + +// InformFSM messages +enum { + fsmNopMessage = 0, + fsmDrvQElChangedMessage = 1, + fsmGetFSIconMessage = 2 +}; + +// Messages passed to the fileSystemCommProc +enum { + ffsNopMessage = 0, + ffsGetIconMessage = 1, + ffsIDDiskMessage = 2, + ffsLoadMessage = 3, + ffsUnloadMessage = 4, + ffsIDVolMountMessage = 5, + ffsInformMessage = 6, + ffsGetIconInfoMessage = 7 +}; + +// Error codes from FSM functions +enum { + fsmFFSNotFoundErr = -431, + fsmBusyFFSErr = -432, + fsmBadFFSNameErr = -433, + fsmBadFSDLenErr = -434, + fsmDuplicateFSIDErr = -435, + fsmBadFSDVersionErr = -436, + fsmNoAlternateStackErr = -437, + fsmUnknownFSMMessageErr = -438 +}; + +// paramBlock for ffsGetIconMessage and fsmGetFSIconMessage +enum { + kLargeIcon = 1 +}; + +enum { // FSMGetIconRec struct + iconBufferPtr = 2, + requestSize = 6, + actualSize = 10, + iconType = 14, + isEjectable = 15, + driveQElemPtr = 16, + fileSystemSpecPtr = 20 +}; + +enum { // VolumeMountInfoHeader struct + vmiLength = 0, + vmiMedia = 2, + vmiFlags = 6, + SIZEOF_VolumeMountInfoHeader = 8 +}; + +enum { // GetVolParmsInfoBuffer struct + vMVersion = 0, + vMAttrib = 2, + vMLocalHand = 6, + vMServerAdr = 10, + vMVolumeGrade = 14, + vMForeignPrivID = 18, + SIZEOF_GetVolParmsInfoBuffer = 20 +}; + +// Finder Flags +enum { + kIsOnDesk = 0x0001, + kColor = 0x000E, + kIsShared = 0x0040, + kHasBeenInited = 0x0100, + kHasCustomIcon = 0x0400, + kIsStationery = 0x0800, + kNameLocked = 0x1000, + kHasBundle = 0x2000, + kIsInvisible = 0x4000, + kIsAlias = 0x8000 +}; + +enum { // FInfo struct + fdType = 0, + fdCreator = 4, + fdFlags = 8, + fdLocation = 10, + fdFldr = 14, + SIZEOF_FInfo = 16 +}; + +enum { // FXInfo struct + fdIconID = 0, + fdUnused = 2, + fdScript = 8, + fdXFlags = 9, + fdComment = 10, + fdPutAway = 12, + SIZEOF_FXInfo = 16 +}; + +enum { // HFileParam/HFileInfo struct + ioFRefNum = 24, + ioFVersNum = 26, + ioFDirIndex = 28, + ioFlAttrib = 30, + ioACUser = 31, + ioFlFndrInfo = 32, + ioDirID = 48, + ioFlStBlk = 52, + ioFlLgLen = 54, + ioFlPyLen = 58, + ioFlRStBlk = 62, + ioFlRLgLen = 64, + ioFlRPyLen = 68, + ioFlCrDat = 72, + ioFlMdDat = 76, + ioFlBkDat = 80, + ioFlXFndrInfo = 84, + ioFlParID = 100, + ioFlClpSiz = 104 +}; + +enum { // DInfo struct + frRect = 0, + frFlags = 8, + frLocation = 10, + frView = 14, + SIZEOF_DInfo = 16 +}; + +enum { // DXInfo struct + frScroll = 0, + frOpenChain = 4, + frScript = 8, + frXFlags = 9, + frComment = 10, + frPutAway = 12, + SIZEOF_DXInfo = 16 +}; + +enum { // HDirParam/DirInfo struct + ioDrUsrWds = 32, + ioDrDirID = 48, + ioDrNmFls = 52, + ioDrCrDat = 72, + ioDrMdDat = 76, + ioDrBkDat = 80, + ioDrFndrInfo = 84, + ioDrParID = 100 +}; + +enum { // WDParam struct + ioWDIndex = 26, + ioWDProcID = 28, + ioWDVRefNum = 32, + ioWDDirID = 48, + SIZEOF_WDParam = 52 +}; + +enum { // HVolumeParam struct + ioVolIndex = 28, + ioVCrDate = 30, + ioVLsMod = 34, + ioVAtrb = 38, + ioVNmFls = 40, + ioVBitMap = 42, + ioAllocPtr = 44, + ioVNmAlBlks = 46, + ioVAlBlkSiz = 48, + ioVClpSiz = 52, + ioAlBlSt = 56, + ioVNxtCNID = 58, + ioVFrBlk = 62, + ioVSigWord = 64, + ioVDrvInfo = 66, + ioVDRefNum = 68, + ioVFSID = 70, + ioVBkUp = 72, + ioVSeqNum = 76, + ioVWrCnt = 78, + ioVFilCnt = 82, + ioVDirCnt = 86, + ioVFndrInfo = 90 +}; + +enum { // CMovePBRec struct + ioNewName = 28, + ioNewDirID = 36 +}; + +enum { // FCBPBRec struct + ioFCBIndx = 28, + ioFCBFlNm = 32, + ioFCBFlags = 36, + ioFCBStBlk = 38, + ioFCBEOF = 40, + ioFCBPLen = 44, + ioFCBCrPs = 48, + ioFCBVRefNum = 52, + ioFCBClpSiz = 54, + ioFCBParID = 58 +}; + +// Volume control block +enum { // VCB struct + vcbFlags = 6, + vcbSigWord = 8, + vcbCrDate = 10, + vcbLsMod = 14, + vcbAtrb = 18, + vcbNmFls = 20, + vcbVBMSt = 22, + vcbAllocPtr = 24, + vcbNmAlBlks = 26, + vcbAlBlkSiz = 28, + vcbClpSiz = 32, + vcbAlBlSt = 36, + vcbNxtCNID = 38, + vcbFreeBks = 42, + vcbVN = 44, + vcbDrvNum = 72, + vcbDRefNum = 74, + vcbFSID = 76, + vcbVRefNum = 78, + vcbMAdr = 80, + vcbBufAdr = 84, + vcbMLen = 88, + vcbDirIndex = 90, + vcbDirBlk = 92, + vcbVolBkUp = 94, + vcbVSeqNum = 98, + vcbWrCnt = 100, + vcbXTClpSiz = 104, + vcbCTClpSiz = 108, + vcbNmRtDirs = 112, + vcbFilCnt = 114, + vcbDirCnt = 118, + vcbFndrInfo = 122, + vcbVCSize = 154, + vcbVBMCSiz = 156, + vcbCtlCSiz = 158, + vcbXTAlBlks = 160, + vcbCTAlBlks = 162, + vcbXTRef = 164, + vcbCTRef = 166, + vcbCtlBuf = 168, + vcbDirIDM = 172, + vcbOffsM = 176, + SIZEOF_VCB = 178 +}; + +// Working directory control block +enum { // WDCBRec struct + wdVCBPtr = 0, + wdDirID = 4, + wdCatHint = 8, + wdProcID = 12, + SIZEOF_WDCBRec = 16 +}; + +// File control block +enum { // FCBRec struct + fcbFlNm = 0, + fcbFlags = 4, + fcbTypByt = 5, + fcbSBlk = 6, + fcbEOF = 8, + fcbPLen = 12, + fcbCrPs = 16, + fcbVPtr = 20, + fcbBfAdr = 24, + fcbFlPos = 28, + fcbClmpSize = 30, + fcbBTCBPtr = 34, + fcbExtRec = 38, + fcbFType = 50, + fcbCatPos = 54, + fcbDirID = 58, + fcbCName = 62 +}; + +enum { // ParsePathRec struct + ppNamePtr = 0, + ppStartOffset = 4, + ppComponentLength = 6, + ppMoreName = 8, + ppFoundDelimiter = 9, + SIZEOF_ParsePathRec = 10 +}; + +enum { // HFSCIRec struct + compInterfMask = 0, + compInterfProc = 4, + log2PhyProc = 8, + stackTop = 12, + stackSize = 16, + stackPtr = 20, + idSector = 28, + SIZEOF_HFSCIRec = 40 +}; + +enum { // DICIRec struct + maxVolNameLength = 8, + blockSize = 10, + SIZEOF_DICIRec = 24 +}; + +enum { // FSDRec struct + fsdLink = 0, + fsdLength = 4, + fsdVersion = 6, + fileSystemFSID = 8, + fileSystemName = 10, + fileSystemSpec = 42, + fileSystemGlobalsPtr = 112, + fileSystemCommProc = 116, + fsdHFSCI = 132, + fsdDICI = 172, + SIZEOF_FSDRec = 196 +}; + +#endif diff --git a/BasiliskII/src/include/macos_util.h b/BasiliskII/src/include/macos_util.h index d593788e..ffa85dd3 100644 --- a/BasiliskII/src/include/macos_util.h +++ b/BasiliskII/src/include/macos_util.h @@ -68,10 +68,24 @@ enum { closErr = -24, abortErr = -27, notOpenErr = -28, + dskFulErr = -34, + nsvErr = -35, ioErr = -36, + bdNamErr = -37, + fnOpnErr = -38, + eofErr = -39, + posErr = -40, + tmfoErr = -42, + fnfErr = -43, wPrErr = -44, + fLckdErr = -45, + fBsyErr = -47, + dupFNErr = -48, paramErr = -50, + rfNumErr = -51, + permErr = -54, nsDrvErr = -56, + extFSErr = -58, noDriveErr = -64, offLinErr = -65, noNybErr = -66, @@ -93,7 +107,8 @@ enum { fmt1Err = -82, fmt2Err = -83, verErr = -84, - memFullErr = -108 + memFullErr = -108, + dirNFErr = -120 }; // Misc constants @@ -156,7 +171,8 @@ enum { // IOParam struct ioActCount = 40, ioPosMode = 44, ioPosOffset = 46, - ioWPosOffset = 46 // Wide positioning offset when ioPosMode has kWidePosOffsetBit set + ioWPosOffset = 46, // Wide positioning offset when ioPosMode has kWidePosOffsetBit set + SIZEOF_IOParam = 50 }; enum { // CntrlParam struct diff --git a/BasiliskII/src/include/main.h b/BasiliskII/src/include/main.h index 6e42d3c2..a903d85a 100644 --- a/BasiliskII/src/include/main.h +++ b/BasiliskII/src/include/main.h @@ -38,7 +38,11 @@ struct M68kRegisters { uint16 sr; }; -// Functions +// General functions +extern bool InitAll(void); +extern void ExitAll(void); + +// Platform-specific functions extern void FlushCodeCache(void *start, uint32 size); // Code was patched, flush caches if neccessary extern void QuitEmulator(void); // Quit emulator extern void ErrorAlert(const char *text); // Display error alert diff --git a/BasiliskII/src/include/user_strings.h b/BasiliskII/src/include/user_strings.h index 324fc60d..e4b860e9 100644 --- a/BasiliskII/src/include/user_strings.h +++ b/BasiliskII/src/include/user_strings.h @@ -83,6 +83,7 @@ enum { STR_BOOT_ANY_LAB, STR_BOOT_CDROM_LAB, STR_NOCDROM_CTRL, + STR_EXTFS_CTRL, STR_DEVICE_CTRL, STR_UNIT_CTRL, STR_ADD_VOLUME_TITLE, @@ -186,7 +187,11 @@ enum { STR_WINDOW_ITEM_ABOUT, STR_WINDOW_ITEM_REFRESH, STR_WINDOW_ITEM_MOUNT, - STR_SUSPEND_WINDOW_TITLE + STR_SUSPEND_WINDOW_TITLE, + + // External file system + STR_EXTFS_NAME = 5000, + STR_EXTFS_VOLUME_NAME }; // Common and platform-specific string definitions diff --git a/BasiliskII/src/main.cpp b/BasiliskII/src/main.cpp new file mode 100644 index 00000000..ab36e1eb --- /dev/null +++ b/BasiliskII/src/main.cpp @@ -0,0 +1,170 @@ +/* + * main.cpp - Startup/shutdown code + * + * Basilisk II (C) 1997-1999 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 + */ + +#include "sysdeps.h" + +#include "cpu_emulation.h" +#include "xpram.h" +#include "timer.h" +#include "sony.h" +#include "disk.h" +#include "cdrom.h" +#include "scsi.h" +#include "extfs.h" +#include "audio.h" +#include "video.h" +#include "serial.h" +#include "ether.h" +#include "clip.h" +#include "rom_patches.h" +#include "user_strings.h" +#include "prefs.h" +#include "main.h" + +#define DEBUG 0 +#include "debug.h" + + +/* + * Initialize everything, returns false on error + */ + +bool InitAll(void) +{ + // Check ROM version + if (!CheckROM()) { + ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR)); + return false; + } + +#if EMULATED_68K + // Set CPU and FPU type (UAE emulation) + switch (ROMVersion) { + case ROM_VERSION_64K: + case ROM_VERSION_PLUS: + case ROM_VERSION_CLASSIC: + CPUType = 0; + FPUType = 0; + TwentyFourBitAddressing = true; + break; + case ROM_VERSION_II: + CPUType = 2; + FPUType = PrefsFindBool("fpu") ? 1 : 0; + TwentyFourBitAddressing = true; + break; + case ROM_VERSION_32: + CPUType = 3; + FPUType = PrefsFindBool("fpu") ? 1 : 0; + TwentyFourBitAddressing = false; + break; + } + CPUIs68060 = false; +#endif + + // Load XPRAM + XPRAMInit(); + + // Set boot volume + int16 i16 = PrefsFindInt16("bootdrive"); + XPRAM[0x78] = i16 >> 8; + XPRAM[0x79] = i16 & 0xff; + i16 = PrefsFindInt16("bootdriver"); + XPRAM[0x7a] = i16 >> 8; + XPRAM[0x7b] = i16 & 0xff; + + // Init drivers + SonyInit(); + DiskInit(); + CDROMInit(); + SCSIInit(); + + // Init external file system + ExtFSInit(); + + // Init serial ports + SerialInit(); + + // Init network + EtherInit(); + + // Init Time Manager + TimerInit(); + + // Init clipboard + ClipInit(); + + // Init audio + AudioInit(); + + // Init video + if (!VideoInit(ROMVersion == ROM_VERSION_64K || ROMVersion == ROM_VERSION_PLUS || ROMVersion == ROM_VERSION_CLASSIC)) + return false; + +#if EMULATED_68K + // Init 680x0 emulation (this also activates the memory system which is needed for PatchROM()) + if (!Init680x0()) + return false; +#endif + + // Install ROM patches + if (!PatchROM()) { + ErrorAlert(GetString(STR_UNSUPPORTED_ROM_TYPE_ERR)); + return false; + } + return true; +} + + +/* + * Deinitialize everything + */ + +void ExitAll(void) +{ + // Save XPRAM + XPRAMExit(); + + // Exit video + VideoExit(); + + // Exit audio + AudioExit(); + + // Exit clipboard + ClipExit(); + + // Exit Time Manager + TimerExit(); + + // Exit serial ports + SerialExit(); + + // Exit network + EtherExit(); + + // Exit external file system + ExtFSExit(); + + // Exit drivers + SCSIExit(); + CDROMExit(); + DiskExit(); + SonyExit(); +} diff --git a/BasiliskII/src/prefs.cpp b/BasiliskII/src/prefs.cpp index 8da3540e..0fb36ae6 100644 --- a/BasiliskII/src/prefs.cpp +++ b/BasiliskII/src/prefs.cpp @@ -36,6 +36,7 @@ prefs_desc common_prefs_items[] = { {"disk", TYPE_STRING, true}, // Device/file names of Mac volumes (disk.cpp) {"floppy", TYPE_STRING, true}, // Device/file names of Mac floppy drives (sony.cpp) {"cdrom", TYPE_STRING, true}, // Device/file names of Mac CD-ROM drives (cdrom.cpp) + {"extfs", TYPE_STRING, false}, // Root path of ExtFS (extfs.cpp) {"scsi0", TYPE_STRING, false}, // SCSI targets for Mac SCSI ID 0..6 (scsi_*.cpp) {"scsi1", TYPE_STRING, false}, {"scsi2", TYPE_STRING, false}, diff --git a/BasiliskII/src/rom_patches.cpp b/BasiliskII/src/rom_patches.cpp index 47f3963e..536c5dc3 100644 --- a/BasiliskII/src/rom_patches.cpp +++ b/BasiliskII/src/rom_patches.cpp @@ -30,6 +30,7 @@ #include "disk.h" #include "cdrom.h" #include "video.h" +#include "extfs.h" #include "prefs.h" #include "rom_patches.h" @@ -45,9 +46,9 @@ uint32 UniversalInfo; // ROM offset of UniversalInfo uint32 PutScrapPatch; // Mac address of PutScrap() patch -static uint32 sony_offset; // ROM offset of .Sony driver -static uint32 serd_offset; // ROM offset of SERD resource (serial drivers) -static uint32 microseconds_offset; // ROM offset of Microseconds() replacement routine +static uint32 sony_offset; // ROM offset of .Sony driver +static uint32 serd_offset; // ROM offset of SERD resource (serial drivers) +static uint32 microseconds_offset; // ROM offset of Microseconds() replacement routine static uint32 memory_dispatch_offset; // ROM offset of MemoryDispatch() replacement routine // Prototypes @@ -646,6 +647,9 @@ void PatchAfterStartup(void) r.a[0] = ROMBaseMac + memory_dispatch_offset; r.d[0] = 0xa05c; Execute68kTrap(0xa247, &r); // SetOSTrapAddress() + + // Install external file system + InstallExtFS(); } diff --git a/BasiliskII/src/user_strings.cpp b/BasiliskII/src/user_strings.cpp index 79b7b9d6..413d029c 100644 --- a/BasiliskII/src/user_strings.cpp +++ b/BasiliskII/src/user_strings.cpp @@ -98,6 +98,7 @@ user_string_def common_strings[] = { {STR_BOOT_ANY_LAB, "Any"}, {STR_BOOT_CDROM_LAB, "CD-ROM"}, {STR_NOCDROM_CTRL, "Disable CD-ROM Driver"}, + {STR_EXTFS_CTRL, "Host Root"}, {STR_DEVICE_CTRL, "Device"}, {STR_UNIT_CTRL, "Unit"}, {STR_ADD_VOLUME_TITLE, "Add Volume"}, @@ -202,5 +203,8 @@ user_string_def common_strings[] = { {STR_WINDOW_ITEM_MOUNT, "Mount"}, {STR_SUSPEND_WINDOW_TITLE, "Basilisk II suspended. Press space to reactivate."}, + {STR_EXTFS_NAME, "Host Directory Tree"}, + {STR_EXTFS_VOLUME_NAME, "Host"}, + {-1, NULL} // End marker };