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