From f8703950aacf758ec069fcf8f0b685c97300f6ee Mon Sep 17 00:00:00 2001 From: Maschell Date: Thu, 9 Jun 2022 22:25:05 +0200 Subject: [PATCH] Add FSA documentation --- Makefile | 2 +- include/mocha/fsa.h | 125 ++++++++++++++++++++++++++++++++++++++++++-- source/fsa.cpp | 30 +++++++++-- 3 files changed, 147 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 99488d1..e343a58 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ CFLAGS := -Wall -Werror -save-temps \ CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -CXXFLAGS := $(CFLAGS) -std=gnu++17 +CXXFLAGS := $(CFLAGS) -std=gnu++20 ASFLAGS := $(MACHDEP) diff --git a/include/mocha/fsa.h b/include/mocha/fsa.h index 9c64c82..eb80cfb 100644 --- a/include/mocha/fsa.h +++ b/include/mocha/fsa.h @@ -7,28 +7,145 @@ extern "C" { #endif -FSError FSAEx_Mount(FSClient *client, const char *source, const char *target, uint32_t flags, void *arg_buf, uint32_t arg_len); +typedef enum FSAMountFlags { + FSA_MOUNT_FLAG_LOCAL_MOUNT = 0, + FSA_MOUNT_FLAG_BIND_MOUNT = 1, + FSA_MOUNT_FLAG_GLOBAL_MOUNT = 2, +} FSAMountFlags; -FSError FSAEx_MountEx(int clientHandle, const char *source, const char *target, uint32_t flags, void *arg_buf, uint32_t arg_len); +typedef enum FSAUnmountFlags { + FSA_UNMOUNT_FLAG_BIND_MOUNT = 0x80000000, +} FSAUnmountFlags; -FSError FSAEx_Unmount(FSClient *client, const char *mountedTarget); +/** + * Mounts a source to a given path for a given FSClient (or globally if FSA_MOUNT_FLAG_GLOBAL_MOUNT is set) + * + * @param client valid FSClient pointer with unlocked permissions + * @param source Mount source e.g. /dev/sdcard01 + * @param target Must not start with /vol/storage_ if FSA_MOUNT_FLAG_GLOBAL_MOUNT is **not** set. Requires to start with "/vol/storage_" if FSA_MOUNT_FLAG_GLOBAL_MOUNT or FSA_UNMOUNT_FLAG_BIND_MOUNT is set + * @param flags Determines the mount type. + * @param arg_buf unknown + * @param arg_len unknown + * @return + */ +FSError FSAEx_Mount(FSClient *client, const char *source, const char *target, FSAMountFlags flags, void *arg_buf, uint32_t arg_len); -FSError FSAEx_UnmountEx(int clientHandle, const char *mountedTarget); +/** + * Mounts a source to a given path for a given FSClient (or globally if FSA_MOUNT_FLAG_GLOBAL_MOUNT is set) + * + * @param clientHandle valid /dev/fsa handle with unlocked permissions + * @param source Mount source e.g. /dev/sdcard01 + * @param target Must not start with /vol/storage_ if FSA_MOUNT_FLAG_GLOBAL_MOUNT is **not** set. Requires to start with "/vol/storage_" if FSA_MOUNT_FLAG_GLOBAL_MOUNT is set + * @param flags Determines the mount type. + * @param arg_buf unknown + * @param arg_len unknown + * @return + */ +FSError FSAEx_MountEx(int clientHandle, const char *source, const char *target, FSAMountFlags flags, void *arg_buf, uint32_t arg_len); +/** + * Unmounts a given path + * @param client valid FSClient pointer with unlocked permissions + * @param mountedTarget path where the mount is mounted to. + * @param flags FSA_UNMOUNT_FLAG_BIND_MOUNT is expected for a BindMount + * @return + */ +FSError FSAEx_Unmount(FSClient *client, const char *mountedTarget, FSAUnmountFlags flags); + +/** + * Unmounts a given path + * @param clientHandle valid /dev/fsa handle with unlocked permissions + * @param mountedTarget path where the mount is mounted to. + * @param flags FSA_UNMOUNT_FLAG_BIND_MOUNT is expected for a BindMount + * @return + */ +FSError FSAEx_UnmountEx(int clientHandle, const char *mountedTarget, FSAUnmountFlags flags); + +/** + * Opens a device for raw read/write + * @param client valid FSClient pointer with unlocked permissions + * @param device_path path of the device. e.g. /dev/sdcard01 + * @param outHandle pointer where the handle of the raw device will be stored + * @return + */ FSError FSAEx_RawOpen(FSClient *client, char *device_path, int32_t *outHandle); +/** + * Opens a device for raw read/write + * @param clientHandle valid /dev/fsa handle with unlocked permissions + * @param device_path path of the device. e.g. /dev/sdcard01 + * @param outHandle pointer where the handle of the raw device will be stored + * @return + */ FSError FSAEx_RawOpenEx(int clientHandle, char *device_path, int32_t *outHandle); +/** + * Closes a devices that was previously opened via FSAEx_RawOpen + * @param client valid FSClient pointer with unlocked permissions + * @param device_handle device handle + * @return + */ FSError FSAEx_RawClose(FSClient *client, int32_t device_handle); +/** + * Closes a devices that was previously opened via FSAEx_RawOpen + * @param clientHandle valid /dev/fsa handle with unlocked permissions + * @param device_handle device handle + * @return + */ FSError FSAEx_RawCloseEx(int clientHandle, int32_t device_handle); +/** + * Read data from a device handle. + * + * @param client valid FSClient pointer with unlocked permissions + * @param data buffer where the result will be stored. Requires 0x40 alignment for the buffer itself and buffer size. + * @param size_bytes size of sector. + * @param cnt number of sectors that should be read. + * @param blocks_offset read offset in sectors. + * @param device_handle valid device handle. + * @return + */ FSError FSAEx_RawRead(FSClient *client, void *data, uint32_t size_bytes, uint32_t cnt, uint64_t blocks_offset, int device_handle); +/** + * Read data from a raw device handle. + * + * @param clientHandle valid /dev/fsa handle with unlocked permissions + * @param data buffer where the result will be stored. Requires 0x40 alignment for the buffer itself and buffer size. + * @param size_bytes size of sector. + * @param cnt number of sectors that should be read. + * @param blocks_offset read offset in sectors. + * @param device_handle valid device handle. + * @return + */ FSError FSAEx_RawReadEx(int clientHandle, void *data, uint32_t size_bytes, uint32_t cnt, uint64_t blocks_offset, int device_handle); + +/** + * Write data to raw device handle + * + * @param client valid FSClient pointer with unlocked permissions + * @param data buffer of data that should be written.. Requires 0x40 alignment for the buffer itself and buffer size. + * @param size_bytes size of sector. + * @param cnt number of sectors that should be written. + * @param blocks_offset write offset in sectors. + * @param device_handle valid device handle. + * @return + */ FSError FSAEx_RawWrite(FSClient *client, const void *data, uint32_t size_bytes, uint32_t cnt, uint64_t blocks_offset, int device_handle); +/** + * Write data to raw device handle + * + * @param clientHandle valid /dev/fsa handle with unlocked permissions + * @param data buffer of data that should be written.. Requires 0x40 alignment for the buffer itself and buffer size. + * @param size_bytes size of sector. + * @param cnt number of sectors that should be written. + * @param blocks_offset write offset in sectors. + * @param device_handle valid device handle. + * @return + */ FSError FSAEx_RawWriteEx(int clientHandle, const void *data, uint32_t size_bytes, uint32_t cnt, uint64_t blocks_offset, int device_handle); #ifdef __cplusplus diff --git a/source/fsa.cpp b/source/fsa.cpp index ce0d089..ebe679e 100644 --- a/source/fsa.cpp +++ b/source/fsa.cpp @@ -1,3 +1,4 @@ +#include "mocha/fsa.h" #include "utils.h" #include #include @@ -5,19 +6,38 @@ #include #include #include +#include -FSError FSAEx_Mount(FSClient *client, const char *source, const char *target, uint32_t flags, void *arg_buf, uint32_t arg_len) { +FSError FSAEx_Mount(FSClient *client, const char *source, const char *target, FSAMountFlags flags, void *arg_buf, uint32_t arg_len) { if (!client) { return FS_ERROR_INVALID_CLIENTHANDLE; } return FSAEx_MountEx(FSGetClientBody(client)->clientHandle, source, target, flags, arg_buf, arg_len); } -FSError FSAEx_MountEx(int clientHandle, const char *source, const char *target, uint32_t flags, void *arg_buf, uint32_t arg_len) { +FSError FSAEx_MountEx(int clientHandle, const char *source, const char *target, FSAMountFlags flags, void *arg_buf, uint32_t arg_len) { auto *buffer = (FSAShimBuffer *) memalign(0x40, sizeof(FSAShimBuffer)); if (!buffer) { return FS_ERROR_INVALID_BUFFER; } + + // Check if source and target path is valid. + if (!std::string_view(target).starts_with("/vol/") || !std::string_view(source).starts_with("/dev/")) { + return FS_ERROR_INVALID_PATH; + } + + if (flags == FSA_MOUNT_FLAG_BIND_MOUNT || flags == FSA_MOUNT_FLAG_GLOBAL_MOUNT) { + // Return error if target path DOES NOT start with "/vol/storage_" + if (!std::string_view(target).starts_with("/vol/storage_")) { + return FS_ERROR_INVALID_PATH; + } + } else { + // Return error if target path starts with "/vol/storage_" + if (std::string_view(target).starts_with("/vol/storage_")) { + return FS_ERROR_INVALID_PATH; + } + } + auto res = __FSAShimSetupRequestMount(buffer, clientHandle, source, target, 2, arg_buf, arg_len); if (res != 0) { free(buffer); @@ -28,14 +48,14 @@ FSError FSAEx_MountEx(int clientHandle, const char *source, const char *target, return res; } -FSError FSAEx_Unmount(FSClient *client, const char *mountedTarget, int flags) { +FSError FSAEx_Unmount(FSClient *client, const char *mountedTarget, FSAUnmountFlags flags) { if (!client) { return FS_ERROR_INVALID_CLIENTHANDLE; } - return FSAEx_UnmountEx(FSGetClientBody(client)->clientHandle, mountedTarget); + return FSAEx_UnmountEx(FSGetClientBody(client)->clientHandle, mountedTarget, flags); } -FSError FSAEx_UnmountEx(int clientHandle, const char *mountedTarget, int flags) { +FSError FSAEx_UnmountEx(int clientHandle, const char *mountedTarget, FSAUnmountFlags flags) { auto *buffer = (FSAShimBuffer *) memalign(0x40, sizeof(FSAShimBuffer)); if (!buffer) { return FS_ERROR_INVALID_BUFFER;