diff --git a/Makefile b/Makefile index c5b9f50..b1ea2d8 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ TOPDIR ?= $(CURDIR) include $(DEVKITPRO)/wut/share/wut_rules export VER_MAJOR := 1 -export VER_MINOR := 1 +export VER_MINOR := 2 export VER_PATCH := 0 VERSION := $(VER_MAJOR).$(VER_MINOR).$(VER_PATCH) diff --git a/include/iosuhax.h b/include/iosuhax.h index 4d82752..17d601a 100644 --- a/include/iosuhax.h +++ b/include/iosuhax.h @@ -23,6 +23,7 @@ ***************************************************************************/ #pragma once +#include #include #include @@ -35,8 +36,39 @@ extern "C" { #define DIR_ENTRY_IS_DIRECTORY FS_STAT_FILE #endif -#define FSA_MOUNTFLAGS_BINDMOUNT (1 << 0) -#define FSA_MOUNTFLAGS_GLOBAL (1 << 1) +// Flags for IOSUHAX_FSA_Mount +#define FSA_MOUNTFLAGS_NONE (0 << 0) +#define FSA_MOUNTFLAGS_BINDMOUNT (1 << 0) +#define FSA_MOUNTFLAGS_GLOBAL (1 << 1) + +// Flags for IOSUHAX_FSA_OpenFileEx +#define FSA_OPENFLAGS_NONE (0 << 0) +#define FSA_OPENFLAGS_OPEN_ENCRYPTED (1 << 0) +#define FSA_OPENFLAGS_PREALLOC_SPACE (1 << 1) + +// Flags for posix "open" function to use OPEN_ENCRYPTED flag +#define O_OPEN_ENCRYPTED 0x4000000 + + +typedef struct { + uint8_t unknown[0x1E]; +} __attribute__((packed)) FSFileSystemInfo; +static_assert(sizeof(FSFileSystemInfo) == 0x1E, "FSFileSystemInfo struct is not 0x1E bytes!"); + +typedef struct { + uint8_t unknown1[0x8]; + uint64_t deviceSizeInSectors; + uint32_t deviceSectorSize; + uint8_t unknown2[0x14]; +} __attribute__((packed)) FSDeviceInfo; +static_assert(sizeof(FSDeviceInfo) == 0x28, "FSDeviceInfo struct is not 0x28 bytes!"); + +typedef struct { + uint64_t blocks_count; + uint64_t some_count; + uint32_t block_size; +} __attribute__((packed)) FSBlockInfo; +static_assert(sizeof(FSBlockInfo) == 0x14, "FSBlockInfo struct is not 0x14 bytes!"); int IOSUHAX_Open(const char *dev); // if dev == NULL the default path /dev/iosuhax will be used int IOSUHAX_Close(void); @@ -44,67 +76,71 @@ int IOSUHAX_Close(void); int IOSUHAX_memwrite(uint32_t address, const uint8_t *buffer, uint32_t size); // IOSU external input int IOSUHAX_memread(uint32_t address, uint8_t *out_buffer, uint32_t size); // IOSU external output int IOSUHAX_memcpy(uint32_t dst, uint32_t src, uint32_t size); // IOSU internal memcpy only - int IOSUHAX_kern_write32(uint32_t address, uint32_t value); - int IOSUHAX_kern_read32(uint32_t address, uint32_t *out_buffer, uint32_t count); int IOSUHAX_read_otp(uint8_t *out_buffer, uint32_t size); - int IOSUHAX_read_seeprom(uint8_t *out_buffer, uint32_t offset, uint32_t size); - int IOSUHAX_ODM_GetDiscKey(uint8_t *discKey); - int IOSUHAX_SVC(uint32_t svc_id, uint32_t *args, uint32_t arg_cnt); int IOSUHAX_FSA_Open(); - int IOSUHAX_FSA_Close(int fsaFd); - int IOSUHAX_FSA_Mount(int fsaFd, const char *device_path, const char *volume_path, uint32_t flags, const char *arg_string, int arg_string_len); - int IOSUHAX_FSA_Unmount(int fsaFd, const char *path, uint32_t flags); - int IOSUHAX_FSA_FlushVolume(int fsaFd, const char *volume_path); - -int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char *device_path, int type, uint32_t *out_data); +int IOSUHAX_FSA_RollbackVolume(int fsaFd, const char *volume_path); + +// The FSA_GetDeviceInfo function was mislabeled and is now split into multiple functions +int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char *device_path, FSDeviceInfo *out_data); +int IOSUHAX_FSA_GetFreeSpaceSize(int fsaFd, const char *path, uint64_t *out_data); +int IOSUHAX_FSA_GetDirSize(int fsaFd, const char *path, uint64_t *out_data); +int IOSUHAX_FSA_GetEntryNum(int fsaFd, const char *path, uint32_t *out_data); +int IOSUHAX_FSA_GetFileSystemInfo(int fsaFd, const char *path, FSFileSystemInfo *out_data); +int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, FSStat *out_data); +int IOSUHAX_FSA_GetBadBlockInfo(int fsaFd, const char *path, FSBlockInfo *out_data); +int IOSUHAX_FSA_GetJournalFreeSpaceSize(int fsaFd, const char *path, uint64_t *out_data); +int IOSUHAX_FSA_GetFragmentBlockInfo(int fsaFd, const char *path, FSBlockInfo *out_data); int IOSUHAX_FSA_MakeDir(int fsaFd, const char *path, uint32_t flags); - int IOSUHAX_FSA_OpenDir(int fsaFd, const char *path, int *outHandle); - int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, FSDirectoryEntry *out_data); - int IOSUHAX_FSA_RewindDir(int fsaFd, int dirHandle); - int IOSUHAX_FSA_CloseDir(int fsaFd, int handle); - int IOSUHAX_FSA_ChangeDir(int fsaFd, const char *path); +int IOSUHAX_FSA_GetCwd(int fd, char *out_data, int output_size); -int IOSUHAX_FSA_OpenFile(int fsaFd, const char *path, const char *mode, int *outHandle); +int IOSUHAX_FSA_MakeQuota(int fsaFd, const char *quota_path, uint32_t flags, uint64_t size); +int IOSUHAX_FSA_FlushQuota(int fsaFd, const char *quota_path); +int IOSUHAX_FSA_RollbackQuota(int fsaFd, const char *quota_path); +int IOSUHAX_FSA_RollbackQuotaForce(int fsaFd, const char *quota_path); +int IOSUHAX_FSA_OpenFile(int fsaFd, const char *path, const char *mode, int *outHandle); +int IOSUHAX_FSA_OpenFileEx(int fsaFd, const char *path, const char *mode, int *outHandle, uint32_t create_mode, uint32_t flags, uint32_t prealloc_size); int IOSUHAX_FSA_ReadFile(int fsaFd, void *data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags); - int IOSUHAX_FSA_WriteFile(int fsaFd, const void *data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags); - -int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, FSStat *out_data); - +int IOSUHAX_FSA_ReadFileWithPos(int fsaFd, void *data, uint32_t size, uint32_t cnt, uint32_t pos, int fileHandle, uint32_t flags); +int IOSUHAX_FSA_WriteFileWithPos(int fsaFd, const void *data, uint32_t size, uint32_t cnt, uint32_t pos, int fileHandle, uint32_t flags); +int IOSUHAX_FSA_AppendFile(int fsaFd, uint32_t size, uint32_t cnt, int fileHandle); +int IOSUHAX_FSA_AppendFileEx(int fsaFd, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags); int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle); -int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position); - -int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, FSStat *out_data); +int IOSUHAX_FSA_GetStatFile(int fsaFd, int fileHandle, FSStat *out_data); +int IOSUHAX_FSA_FlushFile(int fsaFd, int fileHandle); +int IOSUHAX_FSA_TruncateFile(int fsaFd, int fileHandle); +int IOSUHAX_FSA_GetPosFile(int fsaFd, int fileHandle, uint32_t *position); +int IOSUHAX_FSA_SetPosFile(int fsaFd, int fileHandle, uint32_t position); +int IOSUHAX_FSA_IsEof(int fsaFd, int fileHandle); int IOSUHAX_FSA_Remove(int fsaFd, const char *path); - +int IOSUHAX_FSA_Rename(int fsaFd, const char *old_path, const char *new_path); int IOSUHAX_FSA_ChangeMode(int fsaFd, const char *path, int mode); +int IOSUHAX_FSA_ChangeModeEx(int fsaFd, const char *path, int mode, int mask); +int IOSUHAX_FSA_ChangeOwner(int fsaFd, const char *path, uint32_t owner, uint32_t group); int IOSUHAX_FSA_RawOpen(int fsaFd, const char *device_path, int *outHandle); - int IOSUHAX_FSA_RawRead(int fsaFd, void *data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle); - int IOSUHAX_FSA_RawWrite(int fsaFd, const void *data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle); - int IOSUHAX_FSA_RawClose(int fsaFd, int device_handle); #ifdef __cplusplus diff --git a/source/iosuhax.c b/source/iosuhax.c index 725e807..806627f 100644 --- a/source/iosuhax.c +++ b/source/iosuhax.c @@ -26,44 +26,67 @@ #include #include -#define IOSUHAX_MAGIC_WORD 0x4E696365 - -#define IOCTL_MEM_WRITE 0x00 -#define IOCTL_MEM_READ 0x01 -#define IOCTL_SVC 0x02 -#define IOCTL_MEMCPY 0x04 -#define IOCTL_REPEATED_WRITE 0x05 -#define IOCTL_KERN_READ32 0x06 -#define IOCTL_KERN_WRITE32 0x07 -#define IOCTL_READ_OTP 0x08 - -#define IOCTL_FSA_OPEN 0x40 -#define IOCTL_FSA_CLOSE 0x41 -#define IOCTL_FSA_MOUNT 0x42 -#define IOCTL_FSA_UNMOUNT 0x43 -#define IOCTL_FSA_GETDEVICEINFO 0x44 -#define IOCTL_FSA_OPENDIR 0x45 -#define IOCTL_FSA_READDIR 0x46 -#define IOCTL_FSA_CLOSEDIR 0x47 -#define IOCTL_FSA_MAKEDIR 0x48 -#define IOCTL_FSA_OPENFILE 0x49 -#define IOCTL_FSA_READFILE 0x4A -#define IOCTL_FSA_WRITEFILE 0x4B -#define IOCTL_FSA_STATFILE 0x4C -#define IOCTL_FSA_CLOSEFILE 0x4D -#define IOCTL_FSA_SETFILEPOS 0x4E -#define IOCTL_FSA_GETSTAT 0x4F -#define IOCTL_FSA_REMOVE 0x50 -#define IOCTL_FSA_REWINDDIR 0x51 -#define IOCTL_FSA_CHDIR 0x52 -#define IOCTL_FSA_RENAME 0x53 -#define IOCTL_FSA_RAW_OPEN 0x54 -#define IOCTL_FSA_RAW_READ 0x55 -#define IOCTL_FSA_RAW_WRITE 0x56 -#define IOCTL_FSA_RAW_CLOSE 0x57 -#define IOCTL_FSA_CHANGEMODE 0x58 -#define IOCTL_FSA_FLUSHVOLUME 0x59 -#define IOCTL_CHECK_IF_IOSUHAX 0x5B +#define IOSUHAX_MAGIC_WORD 0x4E696365 + +#define IOCTL_MEM_WRITE 0x00 +#define IOCTL_MEM_READ 0x01 +#define IOCTL_SVC 0x02 +#define IOCTL_MEMCPY 0x04 +#define IOCTL_REPEATED_WRITE 0x05 +#define IOCTL_KERN_READ32 0x06 +#define IOCTL_KERN_WRITE32 0x07 +#define IOCTL_READ_OTP 0x08 + +#define IOCTL_FSA_OPEN 0x40 +#define IOCTL_FSA_CLOSE 0x41 +#define IOCTL_FSA_MOUNT 0x42 +#define IOCTL_FSA_UNMOUNT 0x43 +#define IOCTL_FSA_GETINFO 0x44 +#define IOCTL_FSA_OPENDIR 0x45 +#define IOCTL_FSA_READDIR 0x46 +#define IOCTL_FSA_CLOSEDIR 0x47 +#define IOCTL_FSA_MAKEDIR 0x48 +#define IOCTL_FSA_OPENFILE 0x49 +#define IOCTL_FSA_READFILE 0x4A +#define IOCTL_FSA_WRITEFILE 0x4B +#define IOCTL_FSA_GETSTATFILE 0x4C +#define IOCTL_FSA_CLOSEFILE 0x4D +#define IOCTL_FSA_SETPOSFILE 0x4E +#define IOCTL_FSA_GETSTAT 0x4F +#define IOCTL_FSA_REMOVE 0x50 +#define IOCTL_FSA_REWINDDIR 0x51 +#define IOCTL_FSA_CHDIR 0x52 +#define IOCTL_FSA_RENAME 0x53 +#define IOCTL_FSA_RAW_OPEN 0x54 +#define IOCTL_FSA_RAW_READ 0x55 +#define IOCTL_FSA_RAW_WRITE 0x56 +#define IOCTL_FSA_RAW_CLOSE 0x57 +#define IOCTL_FSA_CHANGEMODE 0x58 +#define IOCTL_FSA_FLUSHVOLUME 0x59 +#define IOCTL_CHECK_IF_IOSUHAX 0x5B + +// Extended mode +#define IOCTL_FSA_CHANGEOWNER 0x5C +#define IOCTL_FSA_OPENFILEEX 0x5D +#define IOCTL_FSA_READFILEWITHPOS 0x5E +#define IOCTL_FSA_WRITEFILEWITHPOS 0x5F +#define IOCTL_FSA_APPENDFILE 0x60 +#define IOCTL_FSA_APPENDFILEEX 0x61 +#define IOCTL_FSA_FLUSHFILE 0x62 +#define IOCTL_FSA_TRUNCATEFILE 0x63 +#define IOCTL_FSA_GETPOSFILE 0x64 +#define IOCTL_FSA_ISEOF 0x65 +#define IOCTL_FSA_ROLLBACKVOLUME 0x66 +#define IOCTL_FSA_GETCWD 0x67 +#define IOCTL_FSA_MAKEQUOTA 0x68 +#define IOCTL_FSA_FLUSHQUOTA 0x69 +#define IOCTL_FSA_ROLLBACKQUOTA 0x6A +#define IOCTL_FSA_ROLLBACKQUOTAFORCE 0x6B +#define IOCTL_FSA_CHANGEMODEEX 0x6C + +// Old bindings that are now renamed +#define IOCTL_FSA_GETDEVICEINFO IOCTL_FSA_GETINFO +#define IOCTL_FSA_SETFILEPOS IOCTL_FSA_SETPOSFILE static int iosuhaxHandle = -1; @@ -378,13 +401,41 @@ int IOSUHAX_FSA_FlushVolume(int fsaFd, const char *volume_path) { return io_buf[0]; } -int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char *device_path, int type, uint32_t *out_data) { +int IOSUHAX_FSA_RollbackVolume(int fsaFd, const char *volume_path) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(volume_path) + 1; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + strcpy(((char *) io_buf) + io_buf[1], volume_path); + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_ROLLBACKVOLUME, io_buf, io_buf_size, &result, sizeof(result)); + if (res < 0) { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + +int _IOSUHAX_FSA_GetInfo(int fsaFd, const char *path, int type, void *out_data, int out_data_size) { if (iosuhaxHandle < 0) return iosuhaxHandle; const int input_cnt = 3; - int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(device_path) + 1; + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); if (!io_buf) @@ -393,21 +444,57 @@ int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char *device_path, int type, uint io_buf[0] = fsaFd; io_buf[1] = sizeof(uint32_t) * input_cnt; io_buf[2] = type; - strcpy(((char *) io_buf) + io_buf[1], device_path); + strcpy(((char *) io_buf) + io_buf[1], path); uint32_t out_buf[1 + 0x64 / 4]; - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETDEVICEINFO, io_buf, io_buf_size, out_buf, sizeof(out_buf)); + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETINFO, io_buf, io_buf_size, out_buf, sizeof(out_buf)); if (res < 0) { free(io_buf); return res; } - memcpy(out_data, out_buf + 1, 0x64); + memcpy(out_data, out_buf + 1, out_data_size); free(io_buf); return out_buf[0]; } +int IOSUHAX_FSA_GetFreeSpaceSize(int fsaFd, const char *path, uint64_t *out_data) { + return _IOSUHAX_FSA_GetInfo(fsaFd, path, 0, (uint32_t *) out_data, sizeof(uint64_t)); +} + +int IOSUHAX_FSA_GetDirSize(int fsaFd, const char *path, uint64_t *out_data) { + return _IOSUHAX_FSA_GetInfo(fsaFd, path, 1, (uint32_t *) out_data, sizeof(uint64_t)); +} + +int IOSUHAX_FSA_GetEntryNum(int fsaFd, const char *path, uint32_t *out_data) { + return _IOSUHAX_FSA_GetInfo(fsaFd, path, 2, (uint32_t *) out_data, sizeof(uint32_t)); +} + +int IOSUHAX_FSA_GetFileSystemInfo(int fsaFd, const char *path, FSFileSystemInfo *out_data) { + return _IOSUHAX_FSA_GetInfo(fsaFd, path, 3, (uint32_t *) out_data, sizeof(FSFileSystemInfo)); +} + +int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char *device_path, FSDeviceInfo *out_data) { + return _IOSUHAX_FSA_GetInfo(fsaFd, device_path, 4, (uint32_t *) out_data, sizeof(FSDeviceInfo)); +} + +int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, FSStat *out_data) { + return _IOSUHAX_FSA_GetInfo(fsaFd, path, 5, (uint32_t *) out_data, sizeof(FSStat)); +} + +int IOSUHAX_FSA_GetBadBlockInfo(int fsaFd, const char *path, FSBlockInfo *out_data) { + return _IOSUHAX_FSA_GetInfo(fsaFd, path, 6, (uint32_t *) out_data, sizeof(FSBlockInfo)); +} + +int IOSUHAX_FSA_GetJournalFreeSpaceSize(int fsaFd, const char *path, uint64_t *out_data) { + return _IOSUHAX_FSA_GetInfo(fsaFd, path, 7, (uint32_t *) out_data, sizeof(uint64_t)); +} + +int IOSUHAX_FSA_GetFragmentBlockInfo(int fsaFd, const char *path, FSBlockInfo *out_data) { + return _IOSUHAX_FSA_GetInfo(fsaFd, path, 8, (uint32_t *) out_data, sizeof(FSBlockInfo)); +} + int IOSUHAX_FSA_MakeDir(int fsaFd, const char *path, uint32_t flags) { if (iosuhaxHandle < 0) return iosuhaxHandle; @@ -589,6 +676,157 @@ int IOSUHAX_FSA_ChangeDir(int fsaFd, const char *path) { return result; } +int IOSUHAX_FSA_GetCwd(int fsaFd, char *out_path, int out_size) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + if (out_size > 0x27F) out_size = 0x27F; + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = out_size; + + int result_vec_size = 4 + 0x280; + uint8_t *result_vec = (uint8_t *) memalign(0x20, result_vec_size); + if (!result_vec) { + free(io_buf); + return -2; + } + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETCWD, io_buf, io_buf_size, result_vec, result_vec_size); + if (res < 0) { + free(result_vec); + free(io_buf); + return res; + } + + int result = *(int *) result_vec; + strncpy(out_path, (char *) result_vec + 4, out_size); + free(io_buf); + free(result_vec); + return result; +} + +int IOSUHAX_FSA_MakeQuota(int fsaFd, const char *quota_path, uint32_t flags, uint64_t size) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 5; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(quota_path) + 1; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + io_buf[2] = flags; + io_buf[3] = (size >> 32) & 0xFFFFFFFF; + io_buf[4] = size & 0xFFFFFFFF; + strcpy(((char *) io_buf) + io_buf[1], quota_path); + + int result; + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_MAKEDIR, io_buf, io_buf_size, &result, sizeof(result)); + if (res < 0) { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + +int IOSUHAX_FSA_FlushQuota(int fsaFd, const char *quota_path) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(quota_path) + 1; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + strcpy(((char *) io_buf) + io_buf[1], quota_path); + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_FLUSHQUOTA, io_buf, io_buf_size, &result, sizeof(result)); + if (res < 0) { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + +int IOSUHAX_FSA_RollbackQuota(int fsaFd, const char *quota_path) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(quota_path) + 1; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + strcpy(((char *) io_buf) + io_buf[1], quota_path); + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_ROLLBACKQUOTA, io_buf, io_buf_size, &result, sizeof(result)); + if (res < 0) { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + +int IOSUHAX_FSA_RollbackQuotaForce(int fsaFd, const char *quota_path) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(quota_path) + 1; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + strcpy(((char *) io_buf) + io_buf[1], quota_path); + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_ROLLBACKQUOTAFORCE, io_buf, io_buf_size, &result, sizeof(result)); + if (res < 0) { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + int IOSUHAX_FSA_OpenFile(int fsaFd, const char *path, const char *mode, int *outHandle) { if (iosuhaxHandle < 0) return iosuhaxHandle; @@ -620,6 +858,40 @@ int IOSUHAX_FSA_OpenFile(int fsaFd, const char *path, const char *mode, int *out return result_vec[0]; } +int IOSUHAX_FSA_OpenFileEx(int fsaFd, const char *path, const char *mode, int *outHandle, uint32_t create_mode, uint32_t flags, uint32_t prealloc_size) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 6; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + strlen(mode) + 2; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + io_buf[2] = io_buf[1] + strlen(path) + 1; + io_buf[3] = create_mode; + io_buf[4] = flags; + io_buf[5] = prealloc_size; + strcpy(((char *) io_buf) + io_buf[1], path); + strcpy(((char *) io_buf) + io_buf[2], mode); + + int result_vec[2]; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPENFILEEX, io_buf, io_buf_size, result_vec, sizeof(result_vec)); + if (res < 0) { + free(io_buf); + return res; + } + + *outHandle = result_vec[1]; + free(io_buf); + return result_vec[0]; +} + int IOSUHAX_FSA_ReadFile(int fsaFd, void *data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags) { if (iosuhaxHandle < 0) return iosuhaxHandle; @@ -694,7 +966,165 @@ int IOSUHAX_FSA_WriteFile(int fsaFd, const void *data, uint32_t size, uint32_t c return result; } -int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, FSStat *out_data) { +int IOSUHAX_FSA_ReadFileWithPos(int fsaFd, void *data, uint32_t size, uint32_t cnt, uint32_t position, int fileHandle, uint32_t flags) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 6; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = size; + io_buf[2] = cnt; + io_buf[3] = position; + io_buf[4] = fileHandle; + io_buf[5] = flags; + + int out_buf_size = ((size * cnt + 0x40) + 0x3F) & ~0x3F; + + uint32_t *out_buffer = (uint32_t *) memalign(0x40, out_buf_size); + if (!out_buffer) { + free(io_buf); + return -2; + } + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_READFILEWITHPOS, io_buf, io_buf_size, out_buffer, out_buf_size); + if (res < 0) { + free(out_buffer); + free(io_buf); + return res; + } + + //! data is put to offset 0x40 to align the buffer output + memcpy(data, ((uint8_t *) out_buffer) + 0x40, size * cnt); + + int result = out_buffer[0]; + + free(out_buffer); + free(io_buf); + return result; +} + +int IOSUHAX_FSA_WriteFileWithPos(int fsaFd, const void *data, uint32_t size, uint32_t cnt, uint32_t position, int fileHandle, uint32_t flags) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 6; + + int io_buf_size = ((sizeof(uint32_t) * input_cnt + size * cnt + 0x40) + 0x3F) & ~0x3F; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = size; + io_buf[2] = cnt; + io_buf[3] = position; + io_buf[4] = fileHandle; + io_buf[5] = flags; + + //! data is put to offset 0x40 to align the buffer input + memcpy(((uint8_t *) io_buf) + 0x40, data, size * cnt); + + int result; + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_WRITEFILEWITHPOS, io_buf, io_buf_size, &result, sizeof(result)); + if (res < 0) { + free(io_buf); + return res; + } + free(io_buf); + return result; +} + +int IOSUHAX_FSA_AppendFile(int fsaFd, uint32_t size, uint32_t cnt, int fileHandle) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 4; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = size; + io_buf[2] = cnt; + io_buf[3] = fileHandle; + + int result; + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_APPENDFILE, io_buf, io_buf_size, &result, sizeof(result)); + if (res < 0) { + free(io_buf); + return res; + } + free(io_buf); + return result; +} + +int IOSUHAX_FSA_AppendFileEx(int fsaFd, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 5; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = size; + io_buf[2] = cnt; + io_buf[3] = fileHandle; + io_buf[4] = flags; + + int result; + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_APPENDFILEEX, io_buf, io_buf_size, &result, sizeof(result)); + if (res < 0) { + free(io_buf); + return res; + } + free(io_buf); + return result; +} + +int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = fileHandle; + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSEFILE, io_buf, io_buf_size, &result, sizeof(result)); + if (res < 0) { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + +int IOSUHAX_FSA_GetStatFile(int fsaFd, int fileHandle, FSStat *out_data) { if (iosuhaxHandle < 0) return iosuhaxHandle; @@ -716,7 +1146,7 @@ int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, FSStat *out_data) { return -2; } - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_STATFILE, io_buf, io_buf_size, out_buffer, out_buf_size); + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETSTATFILE, io_buf, io_buf_size, out_buffer, out_buf_size); if (res < 0) { free(io_buf); free(out_buffer); @@ -736,7 +1166,7 @@ int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, FSStat *out_data) { return result; } -int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle) { +int IOSUHAX_FSA_FlushFile(int fsaFd, int fileHandle) { if (iosuhaxHandle < 0) return iosuhaxHandle; @@ -753,7 +1183,7 @@ int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle) { int result; - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSEFILE, io_buf, io_buf_size, &result, sizeof(result)); + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_FLUSHFILE, io_buf, io_buf_size, &result, sizeof(result)); if (res < 0) { free(io_buf); return res; @@ -763,11 +1193,11 @@ int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle) { return result; } -int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position) { +int IOSUHAX_FSA_TruncateFile(int fsaFd, int fileHandle) { if (iosuhaxHandle < 0) return iosuhaxHandle; - const int input_cnt = 3; + const int input_cnt = 2; int io_buf_size = sizeof(uint32_t) * input_cnt; @@ -777,11 +1207,10 @@ int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position) { io_buf[0] = fsaFd; io_buf[1] = fileHandle; - io_buf[2] = position; int result; - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_SETFILEPOS, io_buf, io_buf_size, &result, sizeof(result)); + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_TRUNCATEFILE, io_buf, io_buf_size, &result, sizeof(result)); if (res < 0) { free(io_buf); return res; @@ -791,30 +1220,29 @@ int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position) { return result; } -int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, FSStat *out_data) { +int IOSUHAX_FSA_GetPosFile(int fsaFd, int fileHandle, uint32_t *position) { if (iosuhaxHandle < 0) return iosuhaxHandle; const int input_cnt = 2; - int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; + int io_buf_size = sizeof(uint32_t) * input_cnt; uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); if (!io_buf) return -2; io_buf[0] = fsaFd; - io_buf[1] = sizeof(uint32_t) * input_cnt; - strcpy(((char *) io_buf) + io_buf[1], path); + io_buf[1] = fileHandle; - int out_buf_size = 4 + sizeof(FSStat); + int out_buf_size = 4 + sizeof(uint32_t); uint32_t *out_buffer = (uint32_t *) memalign(0x20, out_buf_size); if (!out_buffer) { free(io_buf); return -2; } - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETSTAT, io_buf, io_buf_size, out_buffer, out_buf_size); + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETPOSFILE, io_buf, io_buf_size, out_buffer, out_buf_size); if (res < 0) { free(io_buf); free(out_buffer); @@ -822,15 +1250,65 @@ int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, FSStat *out_data) { } int result = out_buffer[0]; - memcpy(out_data, out_buffer + 1, sizeof(FSStat)); + *position = out_buffer[1]; - // Force FS_STAT_FILE when a size is set. - if ((out_data->flags & FS_STAT_DIRECTORY) != FS_STAT_DIRECTORY && out_data->size > 0) { - out_data->flags |= FS_STAT_FILE; + free(io_buf); + free(out_buffer); + return result; +} + +int IOSUHAX_FSA_SetPosFile(int fsaFd, int fileHandle, uint32_t position) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 3; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = fileHandle; + io_buf[2] = position; + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_SETPOSFILE, io_buf, io_buf_size, &result, sizeof(result)); + if (res < 0) { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + +int IOSUHAX_FSA_IsEof(int fsaFd, int fileHandle) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = fileHandle; + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_ISEOF, io_buf, io_buf_size, &result, sizeof(result)); + if (res < 0) { + free(io_buf); + return res; } free(io_buf); - free(out_buffer); return result; } @@ -858,6 +1336,38 @@ int IOSUHAX_FSA_Remove(int fsaFd, const char *path) { return res; } +int IOSUHAX_FSA_Rename(int fsaFd, const char *old_path, const char *new_path) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 3; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(old_path) + strlen(new_path) + 2; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + memset(io_buf, 0, io_buf_size); + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + io_buf[2] = io_buf[1] + strlen(old_path) + 1; + + strcpy(((char *) io_buf) + io_buf[1], old_path); + strcpy(((char *) io_buf) + io_buf[2], new_path); + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RENAME, io_buf, io_buf_size, &result, sizeof(result)); + if (res < 0) { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + int IOSUHAX_FSA_ChangeMode(int fsaFd, const char *path, int mode) { if (iosuhaxHandle < 0) return iosuhaxHandle; @@ -880,6 +1390,66 @@ int IOSUHAX_FSA_ChangeMode(int fsaFd, const char *path, int mode) { return io_buf[0]; } +int IOSUHAX_FSA_ChangeModeEx(int fsaFd, const char *path, int mode, int mask) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 4; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + io_buf[2] = mode; + io_buf[3] = mask; + strcpy(((char *) io_buf) + io_buf[1], path); + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CHANGEMODEEX, io_buf, io_buf_size, &result, sizeof(result)); + if (res < 0) { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + +int IOSUHAX_FSA_ChangeOwner(int fsaFd, const char *path, uint32_t owner, uint32_t group) { + if (iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 4; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; + + uint32_t *io_buf = (uint32_t *) memalign(0x20, io_buf_size); + if (!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + io_buf[2] = owner; + io_buf[3] = group; + strcpy(((char *) io_buf) + io_buf[1], path); + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CHANGEOWNER, io_buf, io_buf_size, &result, sizeof(result)); + if (res < 0) { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + int IOSUHAX_FSA_RawOpen(int fsaFd, const char *device_path, int *outHandle) { if (iosuhaxHandle < 0) return iosuhaxHandle; diff --git a/source/iosuhax_devoptab.c b/source/iosuhax_devoptab.c index ca80462..43fb718 100644 --- a/source/iosuhax_devoptab.c +++ b/source/iosuhax_devoptab.c @@ -34,10 +34,17 @@ #include #include +#define IOS_ERROR_UNKNOWN_VALUE 0xFFFFFFD6 +#define IOS_ERROR_INVALID_ARG 0xFFFFFFE3 +#define IOS_ERROR_INVALID_SIZE 0xFFFFFFE9 +#define IOS_ERROR_UNKNOWN 0xFFFFFFF7 +#define IOS_ERROR_NOEXISTS 0xFFFFFFFA + typedef struct _fs_dev_private_t { char *mount_path; int fsaFd; int mounted; + bool extended; void *pMutex; } fs_dev_private_t; @@ -45,6 +52,7 @@ typedef struct _fs_dev_file_state_t { fs_dev_private_t *dev; int fd; /* File descriptor */ int flags; /* Opening flags */ + char path[PATH_MAX]; /* Path from opened file */ bool read; /* True if allowed to read from file */ bool write; /* True if allowed to write to file */ bool append; /* True if allowed to append to file */ @@ -185,6 +193,7 @@ static time_t fs_dev_translate_time(FSTime timeValue) { } static int fs_dev_open_r(struct _reent *r, void *fileStruct, const char *path, int flags, int mode) { + // Get device data from path fs_dev_private_t *dev = fs_dev_get_device_data(path); if (!dev) { r->_errno = ENODEV; @@ -197,63 +206,55 @@ static int fs_dev_open_r(struct _reent *r, void *fileStruct, const char *path, i // Determine which mode the file is opened for file->flags = flags; - const char *fsMode; - // Map flags to open modes - if (flags == 0) { + const char *fsMode; + if ((flags & 0x03) == O_RDONLY) { file->read = true; file->write = false; file->append = false; fsMode = "r"; - } else if (flags == 2) { - file->read = true; - file->write = true; - file->append = false; - fsMode = "r+"; - } else if (flags == 0x601) { - file->read = false; - file->write = true; - file->append = false; - fsMode = "w"; - } else if (flags == 0x602) { - file->read = true; - file->write = true; - file->append = false; - fsMode = "w+"; - } else if (flags == 0x209) { + } else if ((flags & 0x03) == O_WRONLY) { file->read = false; file->write = true; - file->append = true; - fsMode = "a"; - } else if (flags == 0x20A) { + file->append = (flags & O_APPEND); + fsMode = file->append ? "a" : "w"; + } else if ((flags & 0x03) == O_RDWR) { file->read = true; file->write = true; - file->append = true; - fsMode = "a+"; + file->append = (flags & O_APPEND); + fsMode = file->append ? "a+" : "w+"; } else { r->_errno = EINVAL; return -1; } - - int fd = -1; - OSLockMutex(dev->pMutex); - char *real_path = fs_dev_real_path(path, dev); if (!path) { r->_errno = ENOMEM; OSUnlockMutex(dev->pMutex); return -1; } + strcpy(file->path, real_path); - int result = IOSUHAX_FSA_OpenFile(dev->fsaFd, real_path, fsMode, &fd); + bool openEncrypted = (flags & O_OPEN_ENCRYPTED) == O_OPEN_ENCRYPTED; + int fd = -1; + int result = 0; + // cache whether IOSUHAX_FSA_OpenFileEx is supported to prevent older iosuhax implementations from being slower + // older implementations aren't able to open encrypted files or create files with a specified mode + if (dev->extended) { + result = IOSUHAX_FSA_OpenFileEx(dev->fsaFd, real_path, fsMode, &fd, fs_dev_translate_permission_mode(mode), openEncrypted ? FSA_OPENFLAGS_OPEN_ENCRYPTED : FSA_OPENFLAGS_NONE, 0); + if (result == IOS_ERROR_INVALID_ARG) dev->extended = false; + } + if (!dev->extended) { + result = IOSUHAX_FSA_OpenFile(dev->fsaFd, real_path, fsMode, &fd); + } free(real_path); if (result == 0) { FSStat stats; - result = IOSUHAX_FSA_StatFile(dev->fsaFd, fd, &stats); + result = IOSUHAX_FSA_GetStatFile(dev->fsaFd, fd, &stats); if (result != 0) { IOSUHAX_FSA_CloseFile(dev->fsaFd, fd); r->_errno = fs_dev_translate_error(result); @@ -281,15 +282,14 @@ static int fs_dev_close_r(struct _reent *r, void *fd) { } OSLockMutex(file->dev->pMutex); - int result = IOSUHAX_FSA_CloseFile(file->dev->fsaFd, file->fd); - OSUnlockMutex(file->dev->pMutex); if (result < 0) { r->_errno = fs_dev_translate_error(result); return -1; } + return 0; } @@ -317,8 +317,7 @@ static off_t fs_dev_seek_r(struct _reent *r, void *fd, off_t pos, int dir) { return -1; } - int result = IOSUHAX_FSA_SetFilePos(file->dev->fsaFd, file->fd, file->pos); - + int result = IOSUHAX_FSA_SetPosFile(file->dev->fsaFd, file->fd, file->pos); OSUnlockMutex(file->dev->pMutex); if (result == 0) { @@ -380,7 +379,6 @@ static ssize_t fs_dev_read_r(struct _reent *r, void *fd, char *ptr, size_t len) OSLockMutex(file->dev->pMutex); size_t done = 0; - while (done < len) { size_t read_size = len - done; @@ -402,6 +400,43 @@ static ssize_t fs_dev_read_r(struct _reent *r, void *fd, char *ptr, size_t len) return done; } +static int fs_dev_ftruncate_r(struct _reent *r, void *fd, off_t len) { + fs_dev_file_state_t *file = (fs_dev_file_state_t *) fd; + if (!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + int result = IOSUHAX_FSA_TruncateFile(file->dev->fsaFd, file->fd); + if (result != 0) { + r->_errno = fs_dev_translate_error(result); + OSUnlockMutex(file->dev->pMutex); + return -1; + } + + OSUnlockMutex(file->dev->pMutex); + return 0; +} + +static int fs_dev_fsync_r(struct _reent *r, void *fd) { + fs_dev_file_state_t *file = (fs_dev_file_state_t *) fd; + if (!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + int result = IOSUHAX_FSA_FlushFile(file->dev->fsaFd, file->fd); + if (result != 0) { + r->_errno = fs_dev_translate_error(result); + OSUnlockMutex(file->dev->pMutex); + return -1; + } + + OSUnlockMutex(file->dev->pMutex); + return 0; +} static int fs_dev_fstat_r(struct _reent *r, void *fd, struct stat *st) { fs_dev_file_state_t *file = (fs_dev_file_state_t *) fd; @@ -416,7 +451,7 @@ static int fs_dev_fstat_r(struct _reent *r, void *fd, struct stat *st) { memset(st, 0, sizeof(struct stat)); FSStat stats; - int result = IOSUHAX_FSA_StatFile(file->dev->fsaFd, (int) fd, &stats); + int result = IOSUHAX_FSA_GetStatFile(file->dev->fsaFd, (int) fd, &stats); if (result != 0) { r->_errno = fs_dev_translate_error(result); OSUnlockMutex(file->dev->pMutex); @@ -462,8 +497,9 @@ static int fs_dev_stat_r(struct _reent *r, const char *path, struct stat *st) { FSStat stats; int result = IOSUHAX_FSA_GetStat(dev->fsaFd, real_path, &stats); - free(real_path); + if (result < 0) { + free(real_path); r->_errno = fs_dev_translate_error(result); OSUnlockMutex(dev->pMutex); return -1; @@ -484,6 +520,8 @@ static int fs_dev_stat_r(struct _reent *r, const char *path, struct stat *st) { st->st_ctime = fs_dev_translate_time(stats.created); st->st_mtime = fs_dev_translate_time(stats.modified); + free(real_path); + OSUnlockMutex(dev->pMutex); return 0; } @@ -509,8 +547,8 @@ static int fs_dev_lstat_r(struct _reent *r, const char *path, struct stat *st) { FSStat stats; int result = IOSUHAX_FSA_GetStat(dev->fsaFd, real_path, &stats); - free(real_path); if (result < 0) { + free(real_path); r->_errno = fs_dev_translate_error(result); OSUnlockMutex(dev->pMutex); return -1; @@ -531,6 +569,8 @@ static int fs_dev_lstat_r(struct _reent *r, const char *path, struct stat *st) { st->st_ctime = fs_dev_translate_time(stats.created); st->st_mtime = fs_dev_translate_time(stats.modified); + free(real_path); + OSUnlockMutex(dev->pMutex); return 0; } @@ -557,17 +597,81 @@ static int fs_dev_unlink_r(struct _reent *r, const char *name) { } int result = IOSUHAX_FSA_Remove(dev->fsaFd, real_path); - free(real_path); + if (result < 0) { + r->_errno = fs_dev_translate_error(result); + OSUnlockMutex(dev->pMutex); + return -1; + } + OSUnlockMutex(dev->pMutex); + return 0; +} + +static int fs_dev_rmdir_r(struct _reent *r, const char *name) { + fs_dev_private_t *dev = fs_dev_get_device_data(name); + if (!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + char *real_path = fs_dev_real_path(name, dev); + if (!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + // Check if directory still has files in which case return error + int dirHandle = 0; + int result = 0; + result = IOSUHAX_FSA_OpenDir(dev->fsaFd, real_path, &dirHandle); if (result < 0) { r->_errno = fs_dev_translate_error(result); + free(real_path); + OSUnlockMutex(dev->pMutex); return -1; } - return result; + FSDirectoryEntry *dir_entry = malloc(sizeof(FSDirectoryEntry)); + if (dir_entry == NULL) { + IOSUHAX_FSA_CloseDir(dev->fsaFd, dirHandle); + free(real_path); + r->_errno = fs_dev_translate_error(result); + OSUnlockMutex(dev->pMutex); + return -1; + } + + result = IOSUHAX_FSA_ReadDir(dev->fsaFd, dirHandle, dir_entry); + IOSUHAX_FSA_CloseDir(dev->fsaFd, dirHandle); + free(dir_entry); + if (result == FS_STATUS_OK) { + free(real_path); + r->_errno = ENOTEMPTY; + OSUnlockMutex(dev->pMutex); + return -1; + } else if (result != FS_STATUS_END) { + free(real_path); + r->_errno = fs_dev_translate_error(result); + OSUnlockMutex(dev->pMutex); + return -1; + } + + // Delete folder + result = IOSUHAX_FSA_Remove(dev->fsaFd, real_path); + free(real_path); + + if (result < 0) { + r->_errno = fs_dev_translate_error(result); + OSUnlockMutex(dev->pMutex); + return -1; + } + + OSUnlockMutex(dev->pMutex); + return 0; } static int fs_dev_chdir_r(struct _reent *r, const char *name) { @@ -587,16 +691,15 @@ static int fs_dev_chdir_r(struct _reent *r, const char *name) { } int result = IOSUHAX_FSA_ChangeDir(dev->fsaFd, real_path); - free(real_path); - OSUnlockMutex(dev->pMutex); - if (result < 0) { r->_errno = fs_dev_translate_error(result); + OSUnlockMutex(dev->pMutex); return -1; } + OSUnlockMutex(dev->pMutex); return 0; } @@ -623,19 +726,17 @@ static int fs_dev_rename_r(struct _reent *r, const char *oldName, const char *ne return -1; } - //! TODO - int result = FS_ERROR_UNSUPPORTED_COMMAND; - + int result = IOSUHAX_FSA_Rename(dev->fsaFd, real_oldpath, real_newpath); free(real_oldpath); free(real_newpath); - OSUnlockMutex(dev->pMutex); - if (result < 0) { r->_errno = fs_dev_translate_error(result); + OSUnlockMutex(dev->pMutex); return -1; } + OSUnlockMutex(dev->pMutex); return 0; } @@ -697,6 +798,25 @@ static int fs_dev_chmod_r(struct _reent *r, const char *path, mode_t mode) { return 0; } +static int fs_dev_fchmod_r(struct _reent *r, void *fd, mode_t mode) { + fs_dev_file_state_t *file = (fs_dev_file_state_t *) fd; + if (!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + int result = IOSUHAX_FSA_ChangeMode(file->dev->fsaFd, file->path, fs_dev_translate_permission_mode(mode)); + OSUnlockMutex(file->dev->pMutex); + + if (result < 0) { + r->_errno = fs_dev_translate_error(result); + return -1; + } + + return 0; +} + static int fs_dev_statvfs_r(struct _reent *r, const char *path, struct statvfs *buf) { fs_dev_private_t *dev = fs_dev_get_device_data(path); if (!dev) { @@ -716,10 +836,8 @@ static int fs_dev_statvfs_r(struct _reent *r, const char *path, struct statvfs * return -1; } - uint64_t size; - - int result = IOSUHAX_FSA_GetDeviceInfo(dev->fsaFd, real_path, 0x00, (uint32_t *) &size); - + uint64_t deviceSize; + int result = IOSUHAX_FSA_GetFreeSpaceSize(dev->fsaFd, real_path, &deviceSize); free(real_path); if (result < 0) { @@ -730,33 +848,24 @@ static int fs_dev_statvfs_r(struct _reent *r, const char *path, struct statvfs * // File system block size buf->f_bsize = 512; - // Fundamental file system block size buf->f_frsize = 512; - // Total number of blocks on file system in units of f_frsize - buf->f_blocks = size >> 9; // this is unknown - + buf->f_blocks = deviceSize / buf->f_frsize; // this is unknown // Free blocks available for all and for non-privileged processes - buf->f_bfree = buf->f_bavail = size >> 9; - + buf->f_bfree = buf->f_bavail = deviceSize / buf->f_frsize; // Number of inodes at this point in time - buf->f_files = 0xffffffff; - + buf->f_files = 0xFFFFFFFF; // Free inodes available for all and for non-privileged processes - buf->f_ffree = 0xffffffff; - + buf->f_ffree = 0xFFFFFFFF; // File system id buf->f_fsid = (int) dev; - // Bit mask of f_flag values. buf->f_flag = 0; - // Maximum length of filenames buf->f_namemax = 255; OSUnlockMutex(dev->pMutex); - return 0; } @@ -779,11 +888,8 @@ static DIR_ITER *fs_dev_diropen_r(struct _reent *r, DIR_ITER *dirState, const ch } int dirHandle; - int result = IOSUHAX_FSA_OpenDir(dev->fsaFd, real_path, &dirHandle); - free(real_path); - OSUnlockMutex(dev->pMutex); if (result < 0) { @@ -805,9 +911,7 @@ static int fs_dev_dirclose_r(struct _reent *r, DIR_ITER *dirState) { } OSLockMutex(dirIter->dev->pMutex); - int result = IOSUHAX_FSA_CloseDir(dirIter->dev->fsaFd, dirIter->dirHandle); - OSUnlockMutex(dirIter->dev->pMutex); if (result < 0) { @@ -825,9 +929,7 @@ static int fs_dev_dirreset_r(struct _reent *r, DIR_ITER *dirState) { } OSLockMutex(dirIter->dev->pMutex); - int result = IOSUHAX_FSA_RewindDir(dirIter->dev->fsaFd, dirIter->dirHandle); - OSUnlockMutex(dirIter->dev->pMutex); if (result < 0) { @@ -904,12 +1006,12 @@ static const devoptab_t devops_fs = { .dirnext_r = fs_dev_dirnext_r, .dirclose_r = fs_dev_dirclose_r, .statvfs_r = fs_dev_statvfs_r, - .ftruncate_r = NULL, // fs_dev_ftruncate_r, - .fsync_r = NULL, // fs_dev_fsync_r, + .ftruncate_r = fs_dev_ftruncate_r, + .fsync_r = fs_dev_fsync_r, .deviceData = NULL, .chmod_r = fs_dev_chmod_r, - .fchmod_r = NULL, // fs_dev_fchmod_r, - .rmdir_r = NULL, // fs_dev_rmdir_r, + .fchmod_r = fs_dev_fchmod_r, + .rmdir_r = fs_dev_rmdir_r, .lstat_r = fs_dev_lstat_r, .utimes_r = NULL, }; @@ -954,6 +1056,9 @@ static int fs_dev_add_device(const char *name, const char *mount_path, int fsaFd priv->mounted = isMounted; priv->pMutex = malloc(OS_MUTEX_SIZE); + // assume that the iosuhax implementation supports extended commands by default + priv->extended = true; + if (!priv->pMutex) { free(dev); free(priv);