From 82e0ccfbd75948113a8e99ccc6bab27e20f36f9f Mon Sep 17 00:00:00 2001 From: Cynthia Date: Wed, 28 Jan 2026 05:38:47 +0000 Subject: [PATCH] add in WHB helpers for PCFS/HFIO this mirrors the SD helpers but for Host File I/O, and PCFS when interacting with devkits. Most of these functions are pretty much beat for beat the same as the SD functions, the only real difference is the introduction of Well Known Host Directories which are the recommended way of referencing several 'PATHs' that a developer would commonly use without needing to hardcode paths. --- libraries/libwhb/include/whb/hfio.h | 73 +++++++++++++++++ libraries/libwhb/src/hfio.c | 122 ++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 libraries/libwhb/include/whb/hfio.h create mode 100644 libraries/libwhb/src/hfio.c diff --git a/libraries/libwhb/include/whb/hfio.h b/libraries/libwhb/include/whb/hfio.h new file mode 100644 index 000000000..f48323c10 --- /dev/null +++ b/libraries/libwhb/include/whb/hfio.h @@ -0,0 +1,73 @@ +#pragma once +#include + +/** + * \defgroup whb_hfio Host I/O access + * \ingroup whb + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum WHBWellKnownHostDirectory +{ + //! A way to quickly reference the emulated MLC directory on a attached host + //! pc. + //! + //! You should prefer to use this for compatability (as it will be the same + //! across systems, even with separate paths), and it will usually be fewer + //! characters meaning the actual path can be used by more of the important + //! stuff. + WHB_MLC_HOST_DIRECTORY = 0, + //! A way to quickly reference the emulated SLC directory on a attached host + //! pc. + //! + //! You should prefer to use this for compatability (as it will be the same + //! across systems, even with separate paths), and it will usually be fewer + //! characters meaning the actual path can be used by more of the important + //! stuff. + WHB_SLC_HOST_DIRECTORY = 1, + //! A way to quickly reference the emulated directory of the 'optical disc' + //! on a attached host pc. + //! + //! You should prefer to use this for compatability (as it will be the same + //! across systems, even with separate paths), and it will usually be fewer + //! characters meaning the actual path can be used by more of the important + //! stuff. + WHB_DISC_HOST_DIRECTORY = 2, + //! A way to quickly reference the emulated directory of the current titles + //! save directory. + //! + //! You should prefer to use this for compatability (as it will be the same + //! across systems, even with separate paths), and it will usually be fewer + //! characters meaning the actual path can be used by more of the important + //! stuff. + WHB_SAVE_HOST_DIRECTORY = 3, + //! A way to quickly reference an attached network drive of the host pc. + //! + //! You should prefer to use this for compatability (as it will be the same + //! across systems, even with separate paths), and it will usually be fewer + //! characters meaning the actual path can be used by more of the important + //! stuff. + WHB_NETWORK_DRIVE_HOST_DIRECTORY = 4, +} WHBWellKnownHostDirectory; + +BOOL +WHBMountHostFileIO(); + +char * +WHBGetHostFileIOMountPath(); + +char * +WHBPathForWellKnownHostDirectory(WHBWellKnownHostDirectory directory); + +BOOL +WHBUnmountHostFileIO(); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/libraries/libwhb/src/hfio.c b/libraries/libwhb/src/hfio.c new file mode 100644 index 000000000..6491cfba8 --- /dev/null +++ b/libraries/libwhb/src/hfio.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include + + +static BOOL + sHFIOMounted = FALSE; + +static char + sHFIOMountPath[128] = {0}; + +static FSClient + sHFIOClient; + +BOOL +WHBMountHostFileIO() +{ + FSCmdBlock cmd; + FSMountSource mountSource; + FSStatus result; + + if (sHFIOMounted) { + return TRUE; + } + + FSInit(); + + result = FSAddClient(&sHFIOClient, FS_ERROR_FLAG_ALL); + if (result != FS_STATUS_OK) { + WHBLogPrintf("%s: FSAddClient error %d", __FUNCTION__, result); + return FALSE; + } + + FSInitCmdBlock(&cmd); + result = FSGetMountSource(&sHFIOClient, &cmd, FS_MOUNT_SOURCE_HFIO, &mountSource, FS_ERROR_FLAG_ALL); + if (result < 0) { + WHBLogPrintf("%s: FSGetMountSource error %d", __FUNCTION__, result); + goto fail; + } + + result = FSMount(&sHFIOClient, &cmd, &mountSource, sHFIOMountPath, sizeof(sHFIOMountPath), FS_ERROR_FLAG_ALL); + if (result < 0) { + WHBLogPrintf("%s: FSMount error %d", __FUNCTION__, result); + goto fail; + } + + sHFIOMounted = TRUE; + return TRUE; + +fail: + FSDelClient(&sHFIOClient, FS_ERROR_FLAG_ALL); + return FALSE; +} + +char * +WHBGetHostFileIOMountPath() +{ + return sHFIOMountPath; +} + +char * +WHBPathForWellKnownHostDirectory(WHBWellKnownHostDirectory directory) +{ + // The host path is 128 bytes, and the maximum we can append is 15 bytes, for a final size of 143. + char *finalPath = (char *)MEMAllocFromDefaultHeap(143); + if (finalPath == NULL) { + return NULL; + } + + // Ensure we get a NULL terminator, mimic calloc. + memset(finalPath, 0, 143); + strcat(finalPath, sHFIOMountPath); + strcat(finalPath, "/"); + switch (directory) { + case WHB_MLC_HOST_DIRECTORY: + strcat(finalPath, "%MLC_EMU_DIR"); + break; + case WHB_SLC_HOST_DIRECTORY: + strcat(finalPath, "%SLC_EMU_DIR"); + break; + case WHB_DISC_HOST_DIRECTORY: + strcat(finalPath, "%DISC_EMU_DIR"); + break; + case WHB_SAVE_HOST_DIRECTORY: + strcat(finalPath, "%SAVE_EMU_DIR"); + break; + case WHB_NETWORK_DRIVE_HOST_DIRECTORY: + strcat(finalPath, "%NETWORK"); + break; + } + return finalPath; +} + +BOOL +WHBUnmountHostFileIO() +{ + FSCmdBlock cmd; + FSStatus result; + + if (!sHFIOMounted) { + return TRUE; + } + + FSInitCmdBlock(&cmd); + + result = FSUnmount(&sHFIOClient, &cmd, sHFIOMountPath, FS_ERROR_FLAG_ALL); + if (result < 0) { + WHBLogPrintf("%s: FSUnmount error %d", __FUNCTION__, result); + return FALSE; + } + + result = FSDelClient(&sHFIOClient, FS_ERROR_FLAG_ALL); + if (result < 0) { + WHBLogPrintf("%s: FSDelClient error %d", __FUNCTION__, result); + return FALSE; + } + + sHFIOMounted = FALSE; + return TRUE; +}