Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ jobs:
clang-format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./source ./include
build-lib:
runs-on: ubuntu-latest
needs: clang-format
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: build lib
run: |
docker build . -f Dockerfile.buildlocal -t builder
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/push_image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v4
Expand Down
76 changes: 49 additions & 27 deletions source/devoptab/devoptab_fsa.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include "devoptab_fsa.h"
#include "logger.h"
#include "../logger.h"
#include "mocha/mocha.h"

#include <algorithm>
#include <complex>
#include <coreinit/cache.h>
#include <coreinit/filesystem_fsa.h>
#include <mutex>
Expand Down Expand Up @@ -38,25 +41,28 @@ static const devoptab_t fsa_default_devoptab = {
static bool fsa_initialised = false;
static FSADeviceData fsa_mounts[0x10];

static void fsaResetMount(FSADeviceData *mount, uint32_t id) {
static void fsaResetMount(FSADeviceData *mount, const uint32_t id) {
*mount = {};
memcpy(&mount->device, &fsa_default_devoptab, sizeof(fsa_default_devoptab));
mount->device.name = mount->name;
mount->device.deviceData = mount;
mount->id = id;
mount->setup = false;
mount->mounted = false;
mount->isSDCard = false;
mount->clientHandle = -1;
mount->deviceSizeInSectors = 0;
mount->deviceSectorSize = 0;
memset(mount->mount_path, 0, sizeof(mount->mount_path));
mount->cwd[0] = '/';
mount->cwd[1] = '\0';
memset(mount->mountPath, 0, sizeof(mount->mountPath));
memset(mount->name, 0, sizeof(mount->name));
DCFlushRange(mount, sizeof(*mount));
}

void fsaInit() {
if (!fsa_initialised) {
uint32_t total = sizeof(fsa_mounts) / sizeof(fsa_mounts[0]);
constexpr uint32_t total = std::size(fsa_mounts);
for (uint32_t i = 0; i < total; i++) {
fsaResetMount(&fsa_mounts[i], i);
}
Expand All @@ -67,15 +73,10 @@ void fsaInit() {
std::mutex fsaMutex;

FSADeviceData *fsa_alloc() {
uint32_t i;
uint32_t total = sizeof(fsa_mounts) / sizeof(fsa_mounts[0]);
FSADeviceData *mount;

fsaInit();

for (i = 0; i < total; i++) {
mount = &fsa_mounts[i];
if (!mount->setup) {
for (auto &fsa_mount : fsa_mounts) {
if (FSADeviceData *mount = &fsa_mount; !mount->setup) {
return mount;
}
}
Expand All @@ -86,8 +87,8 @@ FSADeviceData *fsa_alloc() {
static void fsa_free(FSADeviceData *mount) {
FSError res;
if (mount->mounted) {
if ((res = FSAUnmount(mount->clientHandle, mount->mount_path, FSA_UNMOUNT_FLAG_FORCE)) < 0) {
DEBUG_FUNCTION_LINE_WARN("FSAUnmount %s for %s failed: %s", mount->mount_path, mount->name, FSAGetStatusStr(res));
if ((res = FSAUnmount(mount->clientHandle, mount->mountPath, FSA_UNMOUNT_FLAG_FORCE)) < 0) {
DEBUG_FUNCTION_LINE_WARN("FSAUnmount %s for %s failed: %s", mount->mountPath, mount->name, FSAGetStatusStr(res));
}
}
res = FSADelClient(mount->clientHandle);
Expand All @@ -101,18 +102,17 @@ MochaUtilsStatus Mocha_UnmountFS(const char *virt_name) {
if (!virt_name) {
return MOCHA_RESULT_INVALID_ARGUMENT;
}
std::lock_guard<std::mutex> lock(fsaMutex);
uint32_t total = sizeof(fsa_mounts) / sizeof(fsa_mounts[0]);
std::lock_guard lock(fsaMutex);

fsaInit();

for (uint32_t i = 0; i < total; i++) {
FSADeviceData *mount = &fsa_mounts[i];
for (auto &fsa_mount : fsa_mounts) {
FSADeviceData *mount = &fsa_mount;
if (!mount->setup) {
continue;
}
if (strcmp(mount->name, virt_name) == 0) {
std::string removeName = std::string(mount->name).append(":");
const std::string removeName = std::string(mount->name).append(":");
RemoveDevice(removeName.c_str());
fsa_free(mount);
return MOCHA_RESULT_SUCCESS;
Expand All @@ -129,6 +129,9 @@ MochaUtilsStatus Mocha_MountFS(const char *virt_name, const char *dev_path, cons
}

MochaUtilsStatus Mocha_MountFSEx(const char *virt_name, const char *dev_path, const char *mount_path, FSAMountFlags mountFlags, void *mountArgBuf, int mountArgBufLen) {
if (virt_name == nullptr || mount_path == nullptr) {
return MOCHA_RESULT_INVALID_ARGUMENT;
}
if (!mochaInitDone) {
if (Mocha_InitLibrary() != MOCHA_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Mocha_InitLibrary failed");
Expand All @@ -137,7 +140,7 @@ MochaUtilsStatus Mocha_MountFSEx(const char *virt_name, const char *dev_path, co
}

FSAInit();
std::lock_guard<std::mutex> lock(fsaMutex);
std::lock_guard lock(fsaMutex);

FSADeviceData *mount = fsa_alloc();
if (mount == nullptr) {
Expand All @@ -146,6 +149,23 @@ MochaUtilsStatus Mocha_MountFSEx(const char *virt_name, const char *dev_path, co
return MOCHA_RESULT_MAX_CLIENT;
}

// make sure the paths are normalized
std::string normalizedMountPath(mount_path);
std::ranges::replace(normalizedMountPath, '\\', '/');
while (!normalizedMountPath.empty() && (normalizedMountPath.ends_with("/"))) {
normalizedMountPath.pop_back();
}
std::string normalizedDevPath(dev_path ? dev_path : "");
std::ranges::replace(normalizedDevPath, '\\', '/');
while (!normalizedDevPath.empty() && (normalizedDevPath.ends_with("/"))) {
normalizedDevPath.pop_back();
}

// Things like statvfs behave different on sd cards!
if (normalizedDevPath.starts_with("/dev/sdcard01") || normalizedMountPath.starts_with("/vol/external01")) {
mount->isSDCard = true;
}

mount->clientHandle = FSAAddClient(nullptr);
if (mount->clientHandle < 0) {
DEBUG_FUNCTION_LINE_ERR("FSAAddClient() failed: %s", FSAGetStatusStr(static_cast<FSError>(mount->clientHandle)));
Expand All @@ -162,12 +182,12 @@ MochaUtilsStatus Mocha_MountFSEx(const char *virt_name, const char *dev_path, co
mount->mounted = false;

strncpy(mount->name, virt_name, sizeof(mount->name) - 1);
strncpy(mount->mount_path, mount_path, sizeof(mount->mount_path) - 1);
strncpy(mount->mountPath, normalizedMountPath.c_str(), sizeof(mount->mountPath) - 1);
FSError res;
if (dev_path) {
res = FSAMount(mount->clientHandle, dev_path, mount_path, mountFlags, mountArgBuf, mountArgBufLen);
if (!normalizedDevPath.empty()) {
res = FSAMount(mount->clientHandle, normalizedDevPath.c_str(), normalizedMountPath.c_str(), mountFlags, mountArgBuf, mountArgBufLen);
if (res < 0) {
DEBUG_FUNCTION_LINE_ERR("FSAMount(0x%08X, %s, %s, %08X, %p, %08X) failed: %s", mount->clientHandle, dev_path, mount_path, mountFlags, mountArgBuf, mountArgBufLen, FSAGetStatusStr(res));
DEBUG_FUNCTION_LINE_ERR("FSAMount(0x%08X, %s, %s, %08X, %p, %08X) failed: %s", mount->clientHandle, normalizedDevPath.c_str(), normalizedMountPath.c_str(), mountFlags, mountArgBuf, mountArgBufLen, FSAGetStatusStr(res));
fsa_free(mount);
if (res == FS_ERROR_ALREADY_EXISTS) {
return MOCHA_RESULT_ALREADY_EXISTS;
Expand All @@ -179,18 +199,20 @@ MochaUtilsStatus Mocha_MountFSEx(const char *virt_name, const char *dev_path, co
mount->mounted = false;
}

if ((res = FSAChangeDir(mount->clientHandle, mount->mount_path)) < 0) {
DEBUG_FUNCTION_LINE_WARN("FSAChangeDir(0x%08X, %s) failed: %s", mount->clientHandle, mount->mount_path, FSAGetStatusStr(res));
if ((res = FSAChangeDir(mount->clientHandle, mount->mountPath)) < 0) {
DEBUG_FUNCTION_LINE_WARN("FSAChangeDir(0x%08X, %s) failed: %s", mount->clientHandle, mount->mountPath, FSAGetStatusStr(res));
} else {
strncpy(mount->cwd, normalizedMountPath.c_str(), sizeof(mount->mountPath) - 1);
}

FSADeviceInfo deviceInfo;
if ((res = FSAGetDeviceInfo(mount->clientHandle, mount_path, &deviceInfo)) >= 0) {
if ((res = FSAGetDeviceInfo(mount->clientHandle, normalizedMountPath.c_str(), &deviceInfo)) >= 0) {
mount->deviceSizeInSectors = deviceInfo.deviceSizeInSectors;
mount->deviceSectorSize = deviceInfo.deviceSectorSize;
} else {
mount->deviceSizeInSectors = 0xFFFFFFFF;
mount->deviceSectorSize = 512;
DEBUG_FUNCTION_LINE_WARN("Failed to get DeviceInfo for %s: %s", mount_path, FSAGetStatusStr(res));
DEBUG_FUNCTION_LINE_WARN("Failed to get DeviceInfo for %s: %s", normalizedMountPath.c_str(), FSAGetStatusStr(res));
}

if (AddDevice(&mount->device) < 0) {
Expand Down
50 changes: 29 additions & 21 deletions source/devoptab/devoptab_fsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,24 @@
#include <unistd.h>

typedef struct FSADeviceData {
devoptab_t device{};
bool setup{};
bool mounted{};
devoptab_t device;
bool setup;
bool mounted;
bool isSDCard;
uint32_t id{};
char name[32]{};
char mount_path[256]{};
FSAClientHandle clientHandle{};
uint64_t deviceSizeInSectors{};
uint32_t deviceSectorSize{};
} FSADeviceData;
char name[32];
char mountPath[0x80];
char cwd[FS_MAX_PATH + 1];
FSAClientHandle clientHandle;
uint64_t deviceSizeInSectors;
uint32_t deviceSectorSize;
} __fsa_device_t;

/**
* Open file struct
*/
typedef struct
{
//! FS handle
typedef struct {
//! FSA file handle
FSAFileHandle fd;

//! Flags used in open(2)
Expand All @@ -38,7 +39,7 @@ typedef struct
//! Current file offset
uint32_t offset;

//! Path stored for internal path tracking
//! Current file path
char fullPath[FS_MAX_PATH + 1];

//! Guard file access
Expand All @@ -52,17 +53,17 @@ typedef struct
* Open directory struct
*/
typedef struct {
//! Should be set to FS_DIRITER_MAGIC
//! Should be set to FSA_DIRITER_MAGIC
uint32_t magic;

//! FS handle
//! FS directory handle
FSADirectoryHandle fd;

//! Temporary storage for reading entries
FSADirectoryEntry entry_data;

//! Current file path
char name[FS_MAX_PATH + 1];
//! Current directory path
char fullPath[FS_MAX_PATH + 1];

//! Guard dir access
MutexWrapper mutex;
Expand Down Expand Up @@ -105,13 +106,20 @@ int __fsa_fchmod(struct _reent *r, void *fd, mode_t mode);
int __fsa_rmdir(struct _reent *r, const char *name);
int __fsa_utimes(struct _reent *r, const char *filename, const struct timeval times[2]);

// devoptab_fs_utils.c
// devoptab_fsa_utils.c
char *__fsa_fixpath(struct _reent *r, const char *path);
int __fsa_translate_error(FSError error);
mode_t __fsa_translate_stat_mode(FSStat *fsStat);
void __fsa_translate_stat(FSAClientHandle handle, FSStat *fsStat, ino_t ino, struct stat *posStat);
uint32_t __fsa_hashstring(const char *str);

static inline FSMode
__fsa_translate_permission_mode(mode_t mode) {
// Convert normal Unix octal permission bits into CafeOS hexadecimal permission bits
return (FSMode) (((mode & S_IRWXU) << 2) | ((mode & S_IRWXG) << 1) | (mode & S_IRWXO));
}

time_t __fsa_translate_time(FSTime timeValue);
FSMode __fsa_translate_permission_mode(mode_t mode);
mode_t __fsa_translate_stat_mode(FSAStat *fileStat);
void __fsa_translate_stat(FSAStat *fsStat, struct stat *posStat);

#ifdef __cplusplus
}
Expand Down
20 changes: 15 additions & 5 deletions source/devoptab/devoptab_fsa_chdir.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
#include "../logger.h"
#include "devoptab_fsa.h"
#include "logger.h"
#include <mutex>

int __fsa_chdir(struct _reent *r,
const char *path) {
FSError status;

if (!path) {
r->_errno = EINVAL;
return -1;
Expand All @@ -16,15 +14,27 @@ int __fsa_chdir(struct _reent *r,
r->_errno = ENOMEM;
return -1;
}
auto *deviceData = (FSADeviceData *) r->deviceData;
const auto deviceData = static_cast<__fsa_device_t *>(r->deviceData);

status = FSAChangeDir(deviceData->clientHandle, fixedPath);
const FSError status = FSAChangeDir(deviceData->clientHandle, fixedPath);
if (status < 0) {
DEBUG_FUNCTION_LINE_ERR("FSAChangeDir(0x%08X, %s) failed: %s", deviceData->clientHandle, fixedPath, FSAGetStatusStr(status));
free(fixedPath);
r->_errno = __fsa_translate_error(status);
return -1;
}

// Remove trailing '/'
if (fixedPath[0] != '\0') {
if (fixedPath[strlen(fixedPath) - 1] == '/') {
fixedPath[strlen(fixedPath) - 1] = 0;
}
}

if (snprintf(deviceData->cwd, sizeof(deviceData->cwd), "%s", fixedPath) >= static_cast<int>(sizeof(deviceData->cwd))) {
DEBUG_FUNCTION_LINE_WARN("__wut_fsa_chdir: snprintf result was truncated");
}

free(fixedPath);

return 0;
Expand Down
13 changes: 6 additions & 7 deletions source/devoptab/devoptab_fsa_chmod.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
#include "../logger.h"
#include "devoptab_fsa.h"
#include "logger.h"
#include <mutex>
#include <sys/stat.h>

int __fsa_chmod(struct _reent *r,
const char *path,
mode_t mode) {
FSError status;

if (!path) {
r->_errno = EINVAL;
return -1;
Expand All @@ -19,13 +17,14 @@ int __fsa_chmod(struct _reent *r,
return -1;
}

FSMode translatedMode = __fsa_translate_permission_mode(mode);
const FSMode translatedMode = __fsa_translate_permission_mode(mode);

auto *deviceData = (FSADeviceData *) r->deviceData;
const __fsa_device_t *deviceData = static_cast<__fsa_device_t *>(r->deviceData);

status = FSAChangeMode(deviceData->clientHandle, fixedPath, translatedMode);
const FSError status = FSAChangeMode(deviceData->clientHandle, fixedPath, translatedMode);
if (status < 0) {
DEBUG_FUNCTION_LINE_ERR("FSAChangeMode(0x%08X, %s, 0x%X) failed: %s", deviceData->clientHandle, fixedPath, translatedMode, FSAGetStatusStr(status));
DEBUG_FUNCTION_LINE_ERR("FSAChangeMode(0x%08X, %s, 0x%X) failed: %s",
deviceData->clientHandle, fixedPath, translatedMode, FSAGetStatusStr(status));
free(fixedPath);
r->_errno = __fsa_translate_error(status);
return -1;
Expand Down
Loading