diff --git a/core/error.c b/core/error.c index a0bfc05..e4268fc 100644 --- a/core/error.c +++ b/core/error.c @@ -6,7 +6,7 @@ #include "odfs/error.h" -static const char *error_strings[] = { +static const char *const error_strings[] = { [ODFS_OK] = "OK", [ODFS_ERR_NOMEM] = "out of memory", [ODFS_ERR_IO] = "I/O error", diff --git a/core/log.c b/core/log.c index 0987862..b5de9c5 100644 --- a/core/log.c +++ b/core/log.c @@ -9,7 +9,7 @@ #include #include -static const char *level_names[] = { +static const char *const level_names[] = { [ODFS_LOG_FATAL] = "FATAL", [ODFS_LOG_ERROR] = "ERROR", [ODFS_LOG_WARN] = "WARN", @@ -18,7 +18,7 @@ static const char *level_names[] = { [ODFS_LOG_TRACE] = "TRACE", }; -static const char *subsys_names[] = { +static const char *const subsys_names[] = { [ODFS_SUB_NONE] = "", [ODFS_SUB_CORE] = "core", [ODFS_SUB_DOS] = "dos", diff --git a/core/mount.c b/core/mount.c index 0828419..b9b5be0 100644 --- a/core/mount.c +++ b/core/mount.c @@ -34,7 +34,7 @@ extern const odfs_backend_ops_t hfsplus_backend_ops; * UDF and HFS probed independently for standalone media. * For hybrid discs, ISO-family wins unless overridden. */ -static const odfs_backend_ops_t *backend_table[] = { +static const odfs_backend_ops_t *const backend_table[] = { #if ODFS_FEATURE_ISO9660 &iso9660_backend_ops, #endif diff --git a/core/node.c b/core/node.c index 8f415bb..7328377 100644 --- a/core/node.c +++ b/core/node.c @@ -6,7 +6,7 @@ #include "odfs/node.h" -static const char *backend_names[] = { +static const char *const backend_names[] = { [ODFS_BACKEND_NONE] = "none", [ODFS_BACKEND_ISO9660] = "iso9660", [ODFS_BACKEND_ROCK_RIDGE] = "rock_ridge", @@ -17,7 +17,7 @@ static const char *backend_names[] = { [ODFS_BACKEND_CDDA] = "cdda", }; -static const char *kind_names[] = { +static const char *const kind_names[] = { [ODFS_NODE_FILE] = "file", [ODFS_NODE_DIR] = "dir", [ODFS_NODE_SYMLINK] = "symlink", diff --git a/platform/amiga/common/sys_compat.h b/platform/amiga/common/sys_compat.h index 3c485b5..a3a9f99 100644 --- a/platform/amiga/common/sys_compat.h +++ b/platform/amiga/common/sys_compat.h @@ -24,15 +24,15 @@ struct Hook; typedef LONG (*odfs_amiga_interrupt_fn)(APTR data); -extern struct ExecBase *SysBase; -extern struct DosLibrary *DOSBase; - -void odfs_amiga_init_sysbase(void); -struct ExecBase *odfs_amiga_sysbase(void); -struct DosLibrary *odfs_amiga_dosbase(void); +/* + * The library bases one handler instance owns. + */ +typedef struct odfs_amiga_libs { + struct DosLibrary *dos; +} odfs_amiga_libs_t; -int odfs_amiga_open_libraries(void); -void odfs_amiga_close_libraries(void); +int odfs_amiga_open_libraries(odfs_amiga_libs_t *libs); +void odfs_amiga_close_libraries(odfs_amiga_libs_t *libs); void *odfs_amiga_alloc_mem(ULONG size, ULONG flags); void odfs_amiga_free_mem(void *ptr, ULONG size); @@ -55,7 +55,18 @@ void odfs_amiga_free_signal(LONG num); void *odfs_amiga_create_dos_entry(const char *name, LONG type); void odfs_amiga_delete_dos_entry(void *node); -void odfs_amiga_init_interrupt(struct Interrupt *intr, +/* + * An exec Interrupt plus the callback it dispatches to. The trampoline finds + * the function through is_Data, so nothing about the binding is held at file + * scope and every instance can install its own. + */ +typedef struct odfs_amiga_interrupt { + struct Interrupt intr; + odfs_amiga_interrupt_fn fn; + APTR data; +} odfs_amiga_interrupt_t; + +void odfs_amiga_init_interrupt(odfs_amiga_interrupt_t *ai, const char *name, APTR data, odfs_amiga_interrupt_fn code); diff --git a/platform/amiga/handler.h b/platform/amiga/handler.h index 1272130..451433e 100644 --- a/platform/amiga/handler.h +++ b/platform/amiga/handler.h @@ -19,6 +19,7 @@ #include "amiga_target_compat.h" #include "aros_compat.h" +#include "sys_compat.h" #include "odfs/api.h" typedef struct odfs_volume odfs_volume_t; @@ -88,8 +89,7 @@ typedef struct handler_global { odfs_volume_t *current_volume;/* current mounted volume state */ /* libraries */ - struct ExecBase *sysbase; - struct DosLibrary *dosbase; + odfs_amiga_libs_t libs; /* device I/O */ struct MsgPort *devport; /* device I/O port */ @@ -134,7 +134,7 @@ typedef struct handler_global { /* media change */ struct MsgPort *chgport; /* media change signal port */ struct IOStdReq *chgreq; /* media change I/O request */ - struct Interrupt changeint; /* TD_ADDCHANGEINT callback */ + odfs_amiga_interrupt_t changeint; /* TD_ADDCHANGEINT callback + binding */ odfs_changeint_data_t changeint_data; /* callback payload */ LONG chgsigbit; /* signal bit for media change */ int chg_installed; /* TD_CHANGEINT installed? */ diff --git a/platform/amiga/handler_main.c b/platform/amiga/handler_main.c index a2ed73f..21af83b 100644 --- a/platform/amiga/handler_main.c +++ b/platform/amiga/handler_main.c @@ -48,6 +48,10 @@ #include #include +#if !ODFS_AMIGA_OS4 +#define DOSBase (g->libs.dos) +#endif + #include #include "odfs/error.h" @@ -105,7 +109,7 @@ static void unmount_volume(handler_global_t *g); static void free_volume(odfs_volume_t *volume); static void destroy_device_node(struct DeviceNode *devnode); static void destroy_volume_node(struct DeviceList *volnode); -static int detach_volume_node(odfs_volume_t *volume); +static int detach_volume_node(handler_global_t *g, odfs_volume_t *volume); static int publish_volume_node(handler_global_t *g); static void schedule_volume_publish_retry(handler_global_t *g); static void cancel_volume_publish_retry(handler_global_t *g); @@ -1632,7 +1636,7 @@ static int destroy_stale_volume(handler_global_t *g, odfs_volume_t *volume) return 1; if (volume->volnode) { - if (!detach_volume_node(volume)) + if (!detach_volume_node(g, volume)) return 0; destroy_volume_node(volume->volnode); } @@ -4099,6 +4103,8 @@ typedef struct exall_ctx { static odfs_err_t exall_cb(const odfs_node_t *entry, void *ctx) { exall_ctx_t *ec = ctx; + /* named g so the proto/dos.h inlines below find this instance's base */ + handler_global_t *g = ec->g; ULONG key = amiga_node_key(entry); struct ExAllData *slot; struct ExAllData *cursor_before; @@ -4118,8 +4124,7 @@ static odfs_err_t exall_cb(const odfs_node_t *entry, void *ctx) cursor_before = ec->cursor; remaining_before = ec->remaining; slot = ec->cursor; - if (!exall_fill_entry(ec->g, &ec->cursor, &ec->remaining, ec->data, - entry)) { + if (!exall_fill_entry(g, &ec->cursor, &ec->remaining, ec->data, entry)) { ec->full = 1; return ODFS_ERR_EOF; } @@ -5007,11 +5012,13 @@ static void destroy_volume_publish_timer(handler_global_t *g) g->publish_timer_open = 0; } -static int detach_volume_node(odfs_volume_t *volume) +static int detach_volume_node(handler_global_t *g, odfs_volume_t *volume) { struct DeviceList *volnode; int removed; + (void)g; /* OS4 reaches DOS via IDOS, not the instance's base */ + if (!volume || !volume->volnode || !volume->listed) return 1; @@ -5170,8 +5177,9 @@ static int toc_has_data_track(const odfs_toc_t *toc) return 0; } -static int load_cdda_disk_icon_path(cdda_context_t *ctx, const char *path) +static int load_cdda_disk_icon_path(handler_global_t *g, const char *path) { + cdda_context_t *ctx = (cdda_context_t *)g->cdda_ctx; BPTR fh; LONG size; LONG actual; @@ -5228,8 +5236,8 @@ static void load_cdda_disk_icon(handler_global_t *g) if (!ctx || ctx->is_mixed_mode) return; - if (load_cdda_disk_icon_path(ctx, "ENV:Sys/def_cdda.info") || - load_cdda_disk_icon_path(ctx, "ENVARC:Sys/def_cdda.info")) { + if (load_cdda_disk_icon_path(g, "ENV:Sys/def_cdda.info") || + load_cdda_disk_icon_path(g, "ENVARC:Sys/def_cdda.info")) { ODFS_INFO(&g->log, ODFS_SUB_MOUNT, "using def_cdda.info as audio CD Disk.info"); } @@ -5495,8 +5503,9 @@ static void install_media_change(handler_global_t *g) g->changeint_data.sigmask = 1UL << g->chgsigbit; odfs_amiga_init_interrupt(&g->changeint, "odfs-mediachange", &g->changeint_data, changeint_signal); - g->chgreq->io_Data = (APTR)&g->changeint; - g->chgreq->io_Length = sizeof(g->changeint); + /* the device is handed the embedded Interrupt, not our wrapper */ + g->chgreq->io_Data = (APTR)&g->changeint.intr; + g->chgreq->io_Length = sizeof(g->changeint.intr); g->chgreq->io_Flags = 0; SendIO((struct IORequest *)g->chgreq); @@ -5685,8 +5694,6 @@ void handler_main_startup(struct Message *startup_msg) (void)version_string; /* ensure $VER is not optimized out */ - odfs_amiga_init_sysbase(); - g = odfs_amiga_alloc_mem(sizeof(*g), MEMF_PUBLIC | MEMF_CLEAR); if (!g) { /* @@ -5707,7 +5714,6 @@ void handler_main_startup(struct Message *startup_msg) return; } - g->sysbase = odfs_amiga_sysbase(); g->locklist.mlh_Head = (struct MinNode *)&g->locklist.mlh_Tail; g->locklist.mlh_Tail = NULL; g->locklist.mlh_TailPred = (struct MinNode *)&g->locklist.mlh_Head; @@ -5767,7 +5773,7 @@ void handler_main_startup(struct Message *startup_msg) "ODFileSystem " ODFS_GIT_VERSION " (" ODFS_AMIGA_DATE ") starting..."); - if (!odfs_amiga_open_libraries()) { + if (!odfs_amiga_open_libraries(&g->libs)) { ODFS_ERROR(&g->log, ODFS_SUB_CORE, "open dos.library failed"); pkt->dp_Res1 = DOSFALSE; @@ -5776,7 +5782,6 @@ void handler_main_startup(struct Message *startup_msg) odfs_amiga_free_mem(g, sizeof(*g)); return; } - g->dosbase = odfs_amiga_dosbase(); /* * Validate the FileSysStartupMsg before trusting any of its fields. @@ -6152,7 +6157,7 @@ void handler_main_startup(struct Message *startup_msg) deactivate_vector_port(g); #endif - odfs_amiga_close_libraries(); + odfs_amiga_close_libraries(&g->libs); odfs_amiga_free_mem(g, sizeof(*g)); } diff --git a/platform/amiga/libc_stubs.c b/platform/amiga/libc_stubs.c index 97e9563..e02ad34 100644 --- a/platform/amiga/libc_stubs.c +++ b/platform/amiga/libc_stubs.c @@ -8,12 +8,9 @@ */ #include +#include "amiga_target_compat.h" #include -extern struct ExecBase *SysBase; - -int __errno = 0; - void _exit(int status); void _exit(int status) { diff --git a/platform/amiga/os3/amiga_target_compat.h b/platform/amiga/os3/amiga_target_compat.h index d3ab2e7..e0c54db 100644 --- a/platform/amiga/os3/amiga_target_compat.h +++ b/platform/amiga/os3/amiga_target_compat.h @@ -9,6 +9,13 @@ #define ODFS_AMIGA_OS4 0 +#ifndef __NOLIBBASE__ +#define __NOLIBBASE__ +#endif + +struct ExecBase; +#define SysBase (*(struct ExecBase **)4UL) + /* * OS4 V51+ shutdown packet. OS3 DOS never sends it, but accepting it * unconditionally keeps the shared packet loop free of OS conditionals. diff --git a/platform/amiga/os3/sys_compat.c b/platform/amiga/os3/sys_compat.c index 2d72440..f940982 100644 --- a/platform/amiga/os3/sys_compat.c +++ b/platform/amiga/os3/sys_compat.c @@ -4,92 +4,40 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include "amiga_target_compat.h" #include "sys_compat.h" +#include #include -#include -#include #include -struct ExecBase *SysBase; -struct DosLibrary *DOSBase; -struct Library *UtilityBase; - -static odfs_amiga_interrupt_fn interrupt_code; - -/* - * Handler instances started from one seglist (FileSysResource or a - * resident L:ODFileSystem) share this data segment, so the library - * bases above are shared as well. Reference-count the openers under - * Forbid() and close only when the last instance exits; otherwise the - * first shutdown — including a declined second mount of the same - * device — NULLs the bases out from under every surviving instance. - */ -static LONG lib_users; static LONG odfs_amiga_interrupt_entry(APTR data asm("a1")) { - return interrupt_code ? interrupt_code(data) : 0; -} + odfs_amiga_interrupt_t *ai = data; -void odfs_amiga_init_sysbase(void) -{ - SysBase = *((struct ExecBase **)4L); -} - -struct ExecBase *odfs_amiga_sysbase(void) -{ - return SysBase; + return (ai && ai->fn) ? ai->fn(ai->data) : 0; } -struct DosLibrary *odfs_amiga_dosbase(void) +int odfs_amiga_open_libraries(odfs_amiga_libs_t *libs) { - return DOSBase; -} - -int odfs_amiga_open_libraries(void) -{ - int ok = 1; - - /* dos and utility are ROM-resident on V37+, so OpenLibrary cannot - * Wait() here and the Forbid() holds across the opens. */ - Forbid(); - if (lib_users == 0) { - /* - * V37 (Kickstart 2.04) is the real floor: the ExAll path calls - * MatchPatternNoCase() and startup.S may call StackSwap(), both - * V37. Requiring V37 here turns a latent crash on the - * short-lived 2.00 ROMs into a clean load failure. - */ - DOSBase = (struct DosLibrary *) - OpenLibrary((CONST_STRPTR)"dos.library", 37); - if (DOSBase) - UtilityBase = OpenLibrary((CONST_STRPTR)"utility.library", 36); - else - ok = 0; - } - if (ok) - lib_users++; - Permit(); - - return ok; + /* + * V37 (Kickstart 2.04) is the real floor: the ExAll path calls + * MatchPatternNoCase() and startup.S may call StackSwap(), both + * V37. Requiring V37 here turns a latent crash on the + * short-lived 2.00 ROMs into a clean load failure. + */ + libs->dos = (struct DosLibrary *)OpenLibrary((CONST_STRPTR)"dos.library", 37); + return libs->dos != NULL; } -void odfs_amiga_close_libraries(void) +void odfs_amiga_close_libraries(odfs_amiga_libs_t *libs) { - Forbid(); - if (lib_users > 0 && --lib_users == 0) { - if (UtilityBase) { - CloseLibrary(UtilityBase); - UtilityBase = NULL; - } - if (DOSBase) { - CloseLibrary((struct Library *)DOSBase); - DOSBase = NULL; - } + if (libs->dos) { + CloseLibrary((struct Library *)libs->dos); + libs->dos = NULL; } - Permit(); } void *odfs_amiga_alloc_mem(ULONG size, ULONG flags) @@ -174,23 +122,21 @@ void odfs_amiga_delete_dos_entry(void *node) FreeMem(node, sizeof(struct DosList) + 32u); } -void odfs_amiga_init_interrupt(struct Interrupt *intr, +void odfs_amiga_init_interrupt(odfs_amiga_interrupt_t *ai, const char *name, APTR data, odfs_amiga_interrupt_fn code) { - interrupt_code = code; - intr->is_Node.ln_Type = NT_INTERRUPT; - intr->is_Node.ln_Pri = 0; - intr->is_Node.ln_Name = (char *)name; - intr->is_Data = data; - intr->is_Code = (void (*)(void))(APTR)odfs_amiga_interrupt_entry; + ai->fn = code; + ai->data = data; + ai->intr.is_Node.ln_Type = NT_INTERRUPT; + ai->intr.is_Node.ln_Pri = 0; + ai->intr.is_Node.ln_Name = (char *)name; + ai->intr.is_Data = ai; + ai->intr.is_Code = (void (*)(void))(APTR)odfs_amiga_interrupt_entry; } ULONG odfs_amiga_call_hook_pkt(struct Hook *hook, APTR object, APTR message) { - if (!UtilityBase) - return 1; - - return CallHookPkt(hook, object, message); + return CallHookA(hook, (Object *)object, message); } diff --git a/platform/amiga/os4/sys_compat.c b/platform/amiga/os4/sys_compat.c index 0ad7d0a..76ffe58 100644 --- a/platform/amiga/os4/sys_compat.c +++ b/platform/amiga/os4/sys_compat.c @@ -35,8 +35,6 @@ static struct UtilityIFace *utility_iface; */ static LONG lib_users; -static odfs_amiga_interrupt_fn interrupt_code; - /* * V50+ interrupt entry. Soft interrupts fired through Cause() receive * (0, SysBase, is_Data); interrupt servers receive (context, SysBase, @@ -46,33 +44,13 @@ static void odfs_amiga_interrupt_entry(int32 unused, struct ExecBase *sysbase, APTR data) { + odfs_amiga_interrupt_t *ai = data; + (void)unused; (void)sysbase; - if (interrupt_code) - interrupt_code(data); -} - -void odfs_amiga_init_sysbase(void) -{ - /* - * _start establishes SysBase before any other handler code runs. - * As a fallback (e.g. if the entry path ever changes), recover it - * from the classic ExecBase pointer at absolute address 4, which - * the kickstart environment maintains. - */ - if (!SysBase) - SysBase = *((struct ExecBase **)4L); -} - -struct ExecBase *odfs_amiga_sysbase(void) -{ - return SysBase; -} - -struct DosLibrary *odfs_amiga_dosbase(void) -{ - return DOSBase; + if (ai && ai->fn) + ai->fn(ai->data); } static int open_libraries_first(void) @@ -106,7 +84,7 @@ static int open_libraries_first(void) return 1; } -int odfs_amiga_open_libraries(void) +int odfs_amiga_open_libraries(odfs_amiga_libs_t *libs) { int ok = 1; @@ -119,11 +97,15 @@ int odfs_amiga_open_libraries(void) lib_users++; Permit(); + libs->dos = ok ? DOSBase : NULL; return ok; } -void odfs_amiga_close_libraries(void) +void odfs_amiga_close_libraries(odfs_amiga_libs_t *libs) { + /* the instance drops its copy; the bases themselves are refcounted here */ + libs->dos = NULL; + Forbid(); if (lib_users > 0 && --lib_users == 0) { if (utility_iface) { @@ -241,17 +223,20 @@ void odfs_amiga_delete_dos_entry(void *node) FreeDosObject(DOS_DOSLIST, node); } -void odfs_amiga_init_interrupt(struct Interrupt *intr, +void odfs_amiga_init_interrupt(odfs_amiga_interrupt_t *ai, const char *name, APTR data, odfs_amiga_interrupt_fn code) { - interrupt_code = code; - intr->is_Node.ln_Type = NT_INTERRUPT; - intr->is_Node.ln_Pri = 0; - intr->is_Node.ln_Name = (char *)name; - intr->is_Data = data; - intr->is_Code = (void (*)(void))(APTR)odfs_amiga_interrupt_entry; + ai->fn = code; + ai->data = data; + ai->intr.is_Node.ln_Type = NT_INTERRUPT; + ai->intr.is_Node.ln_Pri = 0; + ai->intr.is_Node.ln_Name = (char *)name; + /* is_Data is the wrapper, so the trampoline reaches this instance's + callback without a global to look it up in */ + ai->intr.is_Data = ai; + ai->intr.is_Code = (void (*)(void))(APTR)odfs_amiga_interrupt_entry; } ULONG odfs_amiga_call_hook_pkt(struct Hook *hook, APTR object, APTR message)