mirror of
https://github.com/wiiu-env/libiosuhax.git
synced 2024-12-03 14:34:16 +01:00
first commit of the library
- added multiple functions to communication to /dev/iosuhax over ioctl command - added multi functional devoptab for mounting and/or mapping devices to virtual device names
This commit is contained in:
commit
57e2197d1f
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/*.a
|
||||||
|
/build
|
113
Makefile
Normal file
113
Makefile
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# Clear the implicit built in rules
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(DEVKITPPC)),)
|
||||||
|
$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=<path to>devkitPPC")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITPPC)/wii_rules
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# BUILD is the directory where object files & intermediate files will be placed
|
||||||
|
# SOURCES is a list of directories containing source code
|
||||||
|
# INCLUDES is a list of directories containing extra header files
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := source
|
||||||
|
INCLUDES := iosuhax.h iosuhax_devoptab.h
|
||||||
|
LIBTARGET := libiosuhax.a
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# installation parameters
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBINSTALL := $(PORTLIBS)/lib
|
||||||
|
HDRINSTALL := $(PORTLIBS)/include
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
CFLAGS = -O2 -Wall -Wno-unused $(MACHDEP) $(INCLUDE) -DHAVE_CONFIG_H
|
||||||
|
CXXFLAGS = $(CFLAGS)
|
||||||
|
ASFLAGS := -g
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# any extra libraries we wish to link with the project
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBS :=
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS :=
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
# rules for different file extensions
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
|
||||||
|
|
||||||
|
export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I$(CURDIR)/$(BUILD) -I$(LIBOGC_INC) \
|
||||||
|
-I$(PORTLIBS)/include
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \
|
||||||
|
-L$(LIBOGC_LIB) -L$(PORTLIBS)/lib
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: $(LIBTARGET)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) $(LIBTARGET)
|
||||||
|
|
||||||
|
install: $(LIBTARGET)
|
||||||
|
@[ -d $(LIBINSTALL) ] || mkdir -p $(LIBINSTALL)
|
||||||
|
@[ -d $(HDRINSTALL) ] || mkdir -p $(HDRINSTALL)
|
||||||
|
cp $(foreach incl,$(INCLUDES),$(SOURCES)/$(incl)) $(HDRINSTALL)
|
||||||
|
cp $(LIBTARGET) $(LIBINSTALL)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(LIBTARGET): $(OFILES)
|
||||||
|
@rm -f "../$(LIBTARGET)"
|
||||||
|
@$(AR) rcs "../$(LIBTARGET)" $(OFILES)
|
||||||
|
@echo built $(notdir $@)
|
||||||
|
|
||||||
|
$(LIBDIR)/$(PLATFORM):
|
||||||
|
mkdir -p ../$(LIBDIR)/$(PLATFORM)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
738
source/iosuhax.c
Normal file
738
source/iosuhax.c
Normal file
@ -0,0 +1,738 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2016
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
***************************************************************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <gctypes.h>
|
||||||
|
#include "os_functions.h"
|
||||||
|
#include "iosuhax.h"
|
||||||
|
|
||||||
|
#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_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_REWINDDIR 0x51
|
||||||
|
#define IOCTL_FSA_CHDIR 0x52
|
||||||
|
|
||||||
|
static int iosuhaxHandle = -1;
|
||||||
|
|
||||||
|
int IOSUHAX_Open(void)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle >= 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
iosuhaxHandle = IOS_Open("/dev/iosuhax", 0);
|
||||||
|
return iosuhaxHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_Close(void)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int res = IOS_Close(iosuhaxHandle);
|
||||||
|
iosuhaxHandle = -1;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_memwrite(u32 address, const u8 * buffer, u32 size)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)memalign(0x20, size + 4);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = address;
|
||||||
|
memcpy(io_buf + 1, buffer, size);
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_MEM_WRITE, io_buf, size + 4, 0, 0);
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_memread(u32 address, u8 * out_buffer, u32 size)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
return IOS_Ioctl(iosuhaxHandle, IOCTL_MEM_READ, &address, sizeof(address), out_buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_memcpy(u32 dst, u32 src, u32 size)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
u32 io_buf[3];
|
||||||
|
io_buf[0] = dst;
|
||||||
|
io_buf[1] = src;
|
||||||
|
io_buf[2] = size;
|
||||||
|
|
||||||
|
return IOS_Ioctl(iosuhaxHandle, IOCTL_MEMCPY, io_buf, sizeof(io_buf), 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_SVC(u32 svc_id, u32 * args, u32 arg_cnt)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
u32 arguments[9];
|
||||||
|
arguments[0] = svc_id;
|
||||||
|
|
||||||
|
if(args && arg_cnt)
|
||||||
|
{
|
||||||
|
if(arg_cnt > 8)
|
||||||
|
arg_cnt = 8;
|
||||||
|
|
||||||
|
memcpy(arguments + 1, args, arg_cnt * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result;
|
||||||
|
int ret = IOS_Ioctl(iosuhaxHandle, IOCTL_SVC, arguments, (1 + arg_cnt) * 4, &result, sizeof(result));
|
||||||
|
if(ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_Open(void)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
int fsaFd;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPEN, 0, 0, &fsaFd, sizeof(fsaFd));
|
||||||
|
if(res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
return fsaFd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_Close(int fsaFd)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSE, &fsaFd, sizeof(fsaFd), &fsaFd, sizeof(fsaFd));
|
||||||
|
if(res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
return fsaFd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_Mount(int fsaFd, const char* device_path, const char* volume_path, u32 flags, const char* arg_string, int arg_string_len)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 6;
|
||||||
|
|
||||||
|
int io_buf_size = (sizeof(u32) * input_cnt) + strlen(device_path) + strlen(volume_path) + arg_string_len + 3;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)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(u32) * input_cnt;
|
||||||
|
io_buf[2] = io_buf[1] + strlen(device_path) + 1;
|
||||||
|
io_buf[3] = flags;
|
||||||
|
io_buf[4] = arg_string_len ? ( io_buf[2] + strlen(volume_path) + 1) : 0;
|
||||||
|
io_buf[5] = arg_string_len;
|
||||||
|
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], device_path);
|
||||||
|
strcpy(((char*)io_buf) + io_buf[2], volume_path);
|
||||||
|
|
||||||
|
if(arg_string_len)
|
||||||
|
memcpy(((char*)io_buf) + io_buf[4], arg_string, arg_string_len);
|
||||||
|
|
||||||
|
int mountRes;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_MOUNT, io_buf, io_buf_size, &mountRes, sizeof(mountRes));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return mountRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_Unmount(int fsaFd, const char* path, u32 flags)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 3;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(u32) * input_cnt + strlen(path) + 1;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(u32) * input_cnt;
|
||||||
|
io_buf[2] = flags;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], path);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_UNMOUNT, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char* device_path, int type, u32* out_data)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 3;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(u32) * input_cnt + strlen(device_path) + 1;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(u32) * input_cnt;
|
||||||
|
io_buf[2] = type;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], device_path);
|
||||||
|
|
||||||
|
u32 out_buf[1 + 0x64 / 4];
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETDEVICEINFO, 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);
|
||||||
|
free(io_buf);
|
||||||
|
return out_buf[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_MakeDir(int fsaFd, const char* path, u32 flags)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 3;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(u32) * input_cnt + strlen(path) + 1;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(u32) * input_cnt;
|
||||||
|
io_buf[2] = flags;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], 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_OpenDir(int fsaFd, const char* path, int* outHandle)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(u32) * input_cnt + strlen(path) + 1;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(u32) * input_cnt;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], path);
|
||||||
|
|
||||||
|
int result_vec[2];
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPENDIR, 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_ReadDir(int fsaFd, int handle, directoryEntry_s* out_data)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(u32) * input_cnt;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = handle;
|
||||||
|
|
||||||
|
int result_vec_size = 4 + sizeof(directoryEntry_s);
|
||||||
|
u8 *result_vec = (u8*) memalign(0x20, result_vec_size);
|
||||||
|
if(!result_vec)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_READDIR, 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;
|
||||||
|
memcpy(out_data, result_vec + 4, sizeof(directoryEntry_s));
|
||||||
|
free(io_buf);
|
||||||
|
free(result_vec);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_RewindDir(int fsaFd, int dirHandle)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(u32) * input_cnt;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = dirHandle;
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_REWINDDIR, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_CloseDir(int fsaFd, int handle)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(u32) * input_cnt;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = handle;
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSEDIR, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_ChangeDir(int fsaFd, const char *path)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(u32) * input_cnt + strlen(path) + 1;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(u32) * input_cnt;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], path);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CHDIR, 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;
|
||||||
|
|
||||||
|
const int input_cnt = 3;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(u32) * input_cnt + strlen(path) + strlen(mode) + 2;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(u32) * input_cnt;
|
||||||
|
io_buf[2] = io_buf[1] + strlen(path) + 1;
|
||||||
|
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_OPENFILE, 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, u32 size, u32 cnt, int fileHandle, u32 flags)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 5;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(u32) * input_cnt;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)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 out_buf_size = ((size * cnt + 0x40) + 0x3F) & ~0x3F;
|
||||||
|
|
||||||
|
u32 *out_buffer = (u32*)memalign(0x40, out_buf_size);
|
||||||
|
if(!out_buffer)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_READFILE, 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, ((u8*)out_buffer) + 0x40, size * cnt);
|
||||||
|
|
||||||
|
int result = out_buffer[0];
|
||||||
|
|
||||||
|
free(out_buffer);
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_WriteFile(int fsaFd, const void* data, u32 size, u32 cnt, int fileHandle, u32 flags)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 5;
|
||||||
|
|
||||||
|
int io_buf_size = ((sizeof(u32) * input_cnt + 0x40) + 0x3F) & ~0x3F;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)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;
|
||||||
|
|
||||||
|
//! data is put to offset 0x40 to align the buffer input
|
||||||
|
memcpy(((u8*)io_buf) + 0x40, data, size * cnt);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_WRITEFILE, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, fileStat_s* out_data)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(u32) * input_cnt;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = fileHandle;
|
||||||
|
|
||||||
|
int out_buf_size = 4 + sizeof(fileStat_s);
|
||||||
|
u32 *out_buffer = (u32*)memalign(0x20, out_buf_size);
|
||||||
|
if(!out_buffer)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_STATFILE, io_buf, io_buf_size, out_buffer, out_buf_size);
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
free(out_buffer);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = out_buffer[0];
|
||||||
|
memcpy(out_data, out_buffer + 1, sizeof(fileStat_s));
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
free(out_buffer);
|
||||||
|
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(u32) * input_cnt;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)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_SetFilePos(int fsaFd, int fileHandle, u32 position)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 3;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(u32) * input_cnt;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)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_SETFILEPOS, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, fileStat_s* out_data)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(u32) * input_cnt + strlen(path) + 1;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(u32) * input_cnt;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], path);
|
||||||
|
|
||||||
|
int out_buf_size = 4 + sizeof(fileStat_s);
|
||||||
|
u32 *out_buffer = (u32*)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);
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
free(out_buffer);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = out_buffer[0];
|
||||||
|
memcpy(out_data, out_buffer + 1, sizeof(fileStat_s));
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
free(out_buffer);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_Remove(int fsaFd, const char *path)
|
||||||
|
{
|
||||||
|
if(iosuhaxHandle < 0)
|
||||||
|
return iosuhaxHandle;
|
||||||
|
|
||||||
|
const int input_cnt = 2;
|
||||||
|
|
||||||
|
int io_buf_size = sizeof(u32) * input_cnt + strlen(path) + 1;
|
||||||
|
|
||||||
|
u32 *io_buf = (u32*)memalign(0x20, io_buf_size);
|
||||||
|
if(!io_buf)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
io_buf[0] = fsaFd;
|
||||||
|
io_buf[1] = sizeof(u32) * input_cnt;
|
||||||
|
strcpy(((char*)io_buf) + io_buf[1], path);
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETSTAT, io_buf, io_buf_size, &result, sizeof(result));
|
||||||
|
if(res < 0)
|
||||||
|
{
|
||||||
|
free(io_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(io_buf);
|
||||||
|
return result;
|
||||||
|
}
|
100
source/iosuhax.h
Normal file
100
source/iosuhax.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2016
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef _LIB_IOSUHAX_H_
|
||||||
|
#define _LIB_IOSUHAX_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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
|
||||||
|
{
|
||||||
|
u32 flag;
|
||||||
|
u32 permission;
|
||||||
|
u32 owner_id;
|
||||||
|
u32 group_id;
|
||||||
|
u32 size; // size in bytes
|
||||||
|
u32 physsize; // physical size on disk in bytes
|
||||||
|
u32 unk[3];
|
||||||
|
u32 id;
|
||||||
|
u32 ctime;
|
||||||
|
u32 mtime;
|
||||||
|
u32 unk2[0x0D];
|
||||||
|
}fileStat_s;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
fileStat_s stat;
|
||||||
|
char name[0x100];
|
||||||
|
}directoryEntry_s;
|
||||||
|
|
||||||
|
#define DIR_ENTRY_IS_DIRECTORY 0x80000000
|
||||||
|
|
||||||
|
#define FSA_MOUNTFLAGS_BINDMOUNT (1 << 0)
|
||||||
|
#define FSA_MOUNTFLAGS_GLOBAL (1 << 1)
|
||||||
|
|
||||||
|
int IOSUHAX_Open(void);
|
||||||
|
int IOSUHAX_Close(void);
|
||||||
|
|
||||||
|
int IOSUHAX_memwrite(u32 address, const u8 * buffer, u32 size); // IOSU external input
|
||||||
|
int IOSUHAX_memread(u32 address, u8 * out_buffer, u32 size); // IOSU external output
|
||||||
|
int IOSUHAX_memcpy(u32 dst, u32 src, u32 size); // IOSU internal memcpy only
|
||||||
|
|
||||||
|
int IOSUHAX_SVC(u32 svc_id, u32 * args, u32 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, u32 flags, const char* arg_string, int arg_string_len);
|
||||||
|
int IOSUHAX_FSA_Unmount(int fsaFd, const char* path, u32 flags);
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char* device_path, int type, u32* out_data);
|
||||||
|
|
||||||
|
int IOSUHAX_FSA_MakeDir(int fsaFd, const char* path, u32 flags);
|
||||||
|
int IOSUHAX_FSA_OpenDir(int fsaFd, const char* path, int* outHandle);
|
||||||
|
int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, directoryEntry_s* 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_OpenFile(int fsaFd, const char* path, const char* mode, int* outHandle);
|
||||||
|
int IOSUHAX_FSA_ReadFile(int fsaFd, void* data, u32 size, u32 cnt, int fileHandle, u32 flags);
|
||||||
|
int IOSUHAX_FSA_WriteFile(int fsaFd, const void* data, u32 size, u32 cnt, int fileHandle, u32 flags);
|
||||||
|
int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, fileStat_s* out_data);
|
||||||
|
int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle);
|
||||||
|
int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, u32 position);
|
||||||
|
int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, fileStat_s* out_data);
|
||||||
|
int IOSUHAX_FSA_Remove(int fsaFd, const char *path);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
942
source/iosuhax_devoptab.c
Normal file
942
source/iosuhax_devoptab.c
Normal file
@ -0,0 +1,942 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2015
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
***************************************************************************/
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
#include <sys/dirent.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "os_functions.h"
|
||||||
|
#include "iosuhax.h"
|
||||||
|
|
||||||
|
typedef struct _fs_dev_private_t {
|
||||||
|
char *mount_path;
|
||||||
|
int fsaFd;
|
||||||
|
int mounted;
|
||||||
|
void *pMutex;
|
||||||
|
} fs_dev_private_t;
|
||||||
|
|
||||||
|
typedef struct _fs_dev_file_state_t {
|
||||||
|
fs_dev_private_t *dev;
|
||||||
|
int fd; /* File descriptor */
|
||||||
|
int flags; /* Opening flags */
|
||||||
|
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 */
|
||||||
|
u64 pos; /* Current position within the file (in bytes) */
|
||||||
|
u64 len; /* Total length of the file (in bytes) */
|
||||||
|
struct _fs_dev_file_state_t *prevOpenFile; /* The previous entry in a double-linked FILO list of open files */
|
||||||
|
struct _fs_dev_file_state_t *nextOpenFile; /* The next entry in a double-linked FILO list of open files */
|
||||||
|
} fs_dev_file_state_t;
|
||||||
|
|
||||||
|
typedef struct _fs_dev_dir_entry_t {
|
||||||
|
fs_dev_private_t *dev;
|
||||||
|
int dirHandle;
|
||||||
|
} fs_dev_dir_entry_t;
|
||||||
|
|
||||||
|
static fs_dev_private_t *fs_dev_get_device_data(const char *path)
|
||||||
|
{
|
||||||
|
const devoptab_t *devoptab = NULL;
|
||||||
|
char name[128] = {0};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Get the device name from the path
|
||||||
|
strncpy(name, path, 127);
|
||||||
|
strtok(name, ":/");
|
||||||
|
|
||||||
|
// Search the devoptab table for the specified device name
|
||||||
|
// NOTE: We do this manually due to a 'bug' in GetDeviceOpTab
|
||||||
|
// which ignores names with suffixes and causes names
|
||||||
|
// like "ntfs" and "ntfs1" to be seen as equals
|
||||||
|
for (i = 3; i < STD_MAX; i++) {
|
||||||
|
devoptab = devoptab_list[i];
|
||||||
|
if (devoptab && devoptab->name) {
|
||||||
|
if (strcmp(name, devoptab->name) == 0) {
|
||||||
|
return (fs_dev_private_t *)devoptab->deviceData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *fs_dev_real_path (const char *path, fs_dev_private_t *dev)
|
||||||
|
{
|
||||||
|
// Sanity check
|
||||||
|
if (!path)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Move the path pointer to the start of the actual path
|
||||||
|
if (strchr(path, ':') != NULL) {
|
||||||
|
path = strchr(path, ':') + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mount_len = strlen(dev->mount_path);
|
||||||
|
|
||||||
|
char *new_name = (char*)malloc(mount_len + strlen(path) + 1);
|
||||||
|
if(new_name) {
|
||||||
|
strcpy(new_name, dev->mount_path);
|
||||||
|
strcpy(new_name + mount_len, path);
|
||||||
|
return new_name;
|
||||||
|
}
|
||||||
|
return new_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *dev = fs_dev_get_device_data(path);
|
||||||
|
if(!dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fileStruct;
|
||||||
|
|
||||||
|
file->dev = dev;
|
||||||
|
// Determine which mode the file is opened for
|
||||||
|
file->flags = flags;
|
||||||
|
|
||||||
|
const char *mode_str;
|
||||||
|
|
||||||
|
if ((flags & 0x03) == O_RDONLY) {
|
||||||
|
file->read = true;
|
||||||
|
file->write = false;
|
||||||
|
file->append = false;
|
||||||
|
mode_str = "r";
|
||||||
|
} else if ((flags & 0x03) == O_WRONLY) {
|
||||||
|
file->read = false;
|
||||||
|
file->write = true;
|
||||||
|
file->append = (flags & O_APPEND);
|
||||||
|
mode_str = file->append ? "a" : "w";
|
||||||
|
} else if ((flags & 0x03) == O_RDWR) {
|
||||||
|
file->read = true;
|
||||||
|
file->write = true;
|
||||||
|
file->append = (flags & O_APPEND);
|
||||||
|
mode_str = file->append ? "a+" : "r+";
|
||||||
|
} else {
|
||||||
|
r->_errno = EACCES;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_OpenFile(dev->fsaFd, real_path, mode_str, &fd);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
if(result == 0)
|
||||||
|
{
|
||||||
|
fileStat_s stats;
|
||||||
|
result = IOSUHAX_FSA_StatFile(dev->fsaFd, fd, &stats);
|
||||||
|
if(result != 0) {
|
||||||
|
IOSUHAX_FSA_CloseFile(dev->fsaFd, fd);
|
||||||
|
r->_errno = result;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
file->fd = fd;
|
||||||
|
file->pos = 0;
|
||||||
|
file->len = stats.size;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return (int)file;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->_errno = result;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int fs_dev_close_r (struct _reent *r, int 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_CloseFile(file->dev->fsaFd, file->fd);
|
||||||
|
|
||||||
|
OSUnlockMutex(file->dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
r->_errno = result;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static off_t fs_dev_seek_r (struct _reent *r, int fd, off_t pos, int dir)
|
||||||
|
{
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd;
|
||||||
|
if(!file->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(file->dev->pMutex);
|
||||||
|
|
||||||
|
switch(dir)
|
||||||
|
{
|
||||||
|
case SEEK_SET:
|
||||||
|
file->pos = pos;
|
||||||
|
break;
|
||||||
|
case SEEK_CUR:
|
||||||
|
file->pos += pos;
|
||||||
|
break;
|
||||||
|
case SEEK_END:
|
||||||
|
file->pos = file->len + pos;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
r->_errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_SetFilePos(file->dev->fsaFd, file->fd, file->pos);
|
||||||
|
|
||||||
|
OSUnlockMutex(file->dev->pMutex);
|
||||||
|
|
||||||
|
if(result == 0)
|
||||||
|
{
|
||||||
|
return file->pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t fs_dev_write_r (struct _reent *r, int fd, const char *ptr, size_t len)
|
||||||
|
{
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd;
|
||||||
|
if(!file->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!file->write)
|
||||||
|
{
|
||||||
|
r->_errno = EACCES;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(file->dev->pMutex);
|
||||||
|
|
||||||
|
size_t done = 0;
|
||||||
|
|
||||||
|
while(done < len)
|
||||||
|
{
|
||||||
|
size_t write_size = len - done;
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_WriteFile(file->dev->fsaFd, ptr + done, 0x01, write_size, file->fd, 0);
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
r->_errno = result;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(result == 0)
|
||||||
|
{
|
||||||
|
if(write_size > 0)
|
||||||
|
done = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
done += result;
|
||||||
|
file->pos += result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OSUnlockMutex(file->dev->pMutex);
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t fs_dev_read_r (struct _reent *r, int fd, char *ptr, size_t len)
|
||||||
|
{
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd;
|
||||||
|
if(!file->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!file->read)
|
||||||
|
{
|
||||||
|
r->_errno = EACCES;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(file->dev->pMutex);
|
||||||
|
|
||||||
|
size_t done = 0;
|
||||||
|
|
||||||
|
while(done < len)
|
||||||
|
{
|
||||||
|
size_t read_size = len - done;
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_ReadFile(file->dev->fsaFd, ptr + done, 0x01, read_size, file->fd, 0);
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
r->_errno = result;
|
||||||
|
done = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(result == 0)
|
||||||
|
{
|
||||||
|
//! TODO: error on read_size > 0
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
done += result;
|
||||||
|
file->pos += result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OSUnlockMutex(file->dev->pMutex);
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int fs_dev_fstat_r (struct _reent *r, int fd, struct stat *st)
|
||||||
|
{
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd;
|
||||||
|
if(!file->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(file->dev->pMutex);
|
||||||
|
|
||||||
|
// Zero out the stat buffer
|
||||||
|
memset(st, 0, sizeof(struct stat));
|
||||||
|
|
||||||
|
fileStat_s stats;
|
||||||
|
int result = IOSUHAX_FSA_StatFile(file->dev->fsaFd, fd, &stats);
|
||||||
|
if(result != 0) {
|
||||||
|
r->_errno = result;
|
||||||
|
OSUnlockMutex(file->dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
st->st_mode = S_IFREG;
|
||||||
|
st->st_size = stats.size;
|
||||||
|
st->st_blocks = (stats.size + 511) >> 9;
|
||||||
|
st->st_nlink = 1;
|
||||||
|
|
||||||
|
// Fill in the generic entry stats
|
||||||
|
st->st_dev = stats.id;
|
||||||
|
st->st_uid = stats.owner_id;
|
||||||
|
st->st_gid = stats.group_id;
|
||||||
|
st->st_ino = stats.id;
|
||||||
|
st->st_atime = stats.mtime;
|
||||||
|
st->st_ctime = stats.ctime;
|
||||||
|
st->st_mtime = stats.mtime;
|
||||||
|
OSUnlockMutex(file->dev->pMutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_ftruncate_r (struct _reent *r, int fd, off_t len)
|
||||||
|
{
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd;
|
||||||
|
if(!file->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->_errno = ENOTSUP;
|
||||||
|
// TODO
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_fsync_r (struct _reent *r, int fd)
|
||||||
|
{
|
||||||
|
fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd;
|
||||||
|
if(!file->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->_errno = ENOTSUP;
|
||||||
|
// TODO
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_stat_r (struct _reent *r, const char *path, struct stat *st)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *dev = fs_dev_get_device_data(path);
|
||||||
|
if(!dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
// Zero out the stat buffer
|
||||||
|
memset(st, 0, sizeof(struct stat));
|
||||||
|
|
||||||
|
char *real_path = fs_dev_real_path(path, dev);
|
||||||
|
if(!real_path) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileStat_s stats;
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_GetStat(dev->fsaFd, real_path, &stats);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
r->_errno = result;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark root also as directory
|
||||||
|
st->st_mode = ((stats.flag & 0x80000000) || (strlen(dev->mount_path) + 1 == strlen(real_path)))? S_IFDIR : S_IFREG;
|
||||||
|
st->st_nlink = 1;
|
||||||
|
st->st_size = stats.size;
|
||||||
|
st->st_blocks = (stats.size + 511) >> 9;
|
||||||
|
// Fill in the generic entry stats
|
||||||
|
st->st_dev = stats.id;
|
||||||
|
st->st_uid = stats.owner_id;
|
||||||
|
st->st_gid = stats.group_id;
|
||||||
|
st->st_ino = stats.id;
|
||||||
|
st->st_atime = stats.mtime;
|
||||||
|
st->st_ctime = stats.ctime;
|
||||||
|
st->st_mtime = stats.mtime;
|
||||||
|
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_link_r (struct _reent *r, const char *existing, const char *newLink)
|
||||||
|
{
|
||||||
|
r->_errno = ENOTSUP;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_unlink_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_Remove(dev->fsaFd, real_path);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
r->_errno = result;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_chdir_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_ChangeDir(dev->fsaFd, real_path);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
r->_errno = result;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *dev = fs_dev_get_device_data(oldName);
|
||||||
|
if(!dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
char *real_oldpath = fs_dev_real_path(oldName, dev);
|
||||||
|
if(!real_oldpath) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
char *real_newpath = fs_dev_real_path(newName, dev);
|
||||||
|
if(!real_newpath) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
free(real_oldpath);
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! TODO
|
||||||
|
int result = -ENOTSUP;
|
||||||
|
|
||||||
|
free(real_oldpath);
|
||||||
|
free(real_newpath);
|
||||||
|
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
r->_errno = result;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_mkdir_r (struct _reent *r, const char *path, int mode)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *dev = fs_dev_get_device_data(path);
|
||||||
|
if(!dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
char *real_path = fs_dev_real_path(path, dev);
|
||||||
|
if(!real_path) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_MakeDir(dev->fsaFd, real_path, mode);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
r->_errno = 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) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
// Zero out the stat buffer
|
||||||
|
memset(buf, 0, sizeof(struct statvfs));
|
||||||
|
|
||||||
|
char *real_path = fs_dev_real_path(path, dev);
|
||||||
|
if(!real_path) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 size;
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_GetDeviceInfo(dev->fsaFd, real_path, 0x00, (u32*)&size);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
if(result < 0) {
|
||||||
|
r->_errno = result;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// Free blocks available for all and for non-privileged processes
|
||||||
|
buf->f_bfree = buf->f_bavail = size >> 9;
|
||||||
|
|
||||||
|
// Number of inodes at this point in time
|
||||||
|
buf->f_files = 0xffffffff;
|
||||||
|
|
||||||
|
// Free inodes available for all and for non-privileged processes
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DIR_ITER *fs_dev_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *dev = fs_dev_get_device_data(path);
|
||||||
|
if(!dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct;
|
||||||
|
|
||||||
|
OSLockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
char *real_path = fs_dev_real_path(path, dev);
|
||||||
|
if(!real_path) {
|
||||||
|
r->_errno = ENOMEM;
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dirHandle;
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_OpenDir(dev->fsaFd, real_path, &dirHandle);
|
||||||
|
|
||||||
|
free(real_path);
|
||||||
|
|
||||||
|
OSUnlockMutex(dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
r->_errno = result;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dirIter->dev = dev;
|
||||||
|
dirIter->dirHandle = dirHandle;
|
||||||
|
|
||||||
|
return dirState;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_dirclose_r (struct _reent *r, DIR_ITER *dirState)
|
||||||
|
{
|
||||||
|
fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct;
|
||||||
|
if(!dirIter->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dirIter->dev->pMutex);
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_CloseDir(dirIter->dev->fsaFd, dirIter->dirHandle);
|
||||||
|
|
||||||
|
OSUnlockMutex(dirIter->dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
r->_errno = result;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_dirreset_r (struct _reent *r, DIR_ITER *dirState)
|
||||||
|
{
|
||||||
|
fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct;
|
||||||
|
if(!dirIter->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dirIter->dev->pMutex);
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_RewindDir(dirIter->dev->fsaFd, dirIter->dirHandle);
|
||||||
|
|
||||||
|
OSUnlockMutex(dirIter->dev->pMutex);
|
||||||
|
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
r->_errno = result;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st)
|
||||||
|
{
|
||||||
|
fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct;
|
||||||
|
if(!dirIter->dev) {
|
||||||
|
r->_errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLockMutex(dirIter->dev->pMutex);
|
||||||
|
|
||||||
|
directoryEntry_s * dir_entry = malloc(sizeof(directoryEntry_s));
|
||||||
|
|
||||||
|
int result = IOSUHAX_FSA_ReadDir(dirIter->dev->fsaFd, dirIter->dirHandle, dir_entry);
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
free(dir_entry);
|
||||||
|
r->_errno = result;
|
||||||
|
OSUnlockMutex(dirIter->dev->pMutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the current entry
|
||||||
|
strcpy(filename, dir_entry->name);
|
||||||
|
|
||||||
|
if(st)
|
||||||
|
{
|
||||||
|
memset(st, 0, sizeof(struct stat));
|
||||||
|
st->st_mode = (dir_entry->stat.flag & 0x80000000) ? S_IFDIR : S_IFREG;
|
||||||
|
st->st_nlink = 1;
|
||||||
|
st->st_size = dir_entry->stat.size;
|
||||||
|
st->st_blocks = (dir_entry->stat.size + 511) >> 9;
|
||||||
|
st->st_dev = dir_entry->stat.id;
|
||||||
|
st->st_uid = dir_entry->stat.owner_id;
|
||||||
|
st->st_gid = dir_entry->stat.group_id;
|
||||||
|
st->st_ino = dir_entry->stat.id;
|
||||||
|
st->st_atime = dir_entry->stat.mtime;
|
||||||
|
st->st_ctime = dir_entry->stat.ctime;
|
||||||
|
st->st_mtime = dir_entry->stat.mtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(dir_entry);
|
||||||
|
OSUnlockMutex(dirIter->dev->pMutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NTFS device driver devoptab
|
||||||
|
static const devoptab_t devops_fs = {
|
||||||
|
NULL, /* Device name */
|
||||||
|
sizeof (fs_dev_file_state_t),
|
||||||
|
fs_dev_open_r,
|
||||||
|
fs_dev_close_r,
|
||||||
|
fs_dev_write_r,
|
||||||
|
fs_dev_read_r,
|
||||||
|
fs_dev_seek_r,
|
||||||
|
fs_dev_fstat_r,
|
||||||
|
fs_dev_stat_r,
|
||||||
|
fs_dev_link_r,
|
||||||
|
fs_dev_unlink_r,
|
||||||
|
fs_dev_chdir_r,
|
||||||
|
fs_dev_rename_r,
|
||||||
|
fs_dev_mkdir_r,
|
||||||
|
sizeof (fs_dev_dir_entry_t),
|
||||||
|
fs_dev_diropen_r,
|
||||||
|
fs_dev_dirreset_r,
|
||||||
|
fs_dev_dirnext_r,
|
||||||
|
fs_dev_dirclose_r,
|
||||||
|
fs_dev_statvfs_r,
|
||||||
|
fs_dev_ftruncate_r,
|
||||||
|
fs_dev_fsync_r,
|
||||||
|
NULL, /* fs_dev_chmod_r */
|
||||||
|
NULL, /* fs_dev_fchmod_r */
|
||||||
|
NULL /* Device data */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int fs_dev_add_device (const char *name, const char *mount_path, int fsaFd, int isMounted)
|
||||||
|
{
|
||||||
|
devoptab_t *dev = NULL;
|
||||||
|
char *devname = NULL;
|
||||||
|
char *devpath = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
if (!name) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a devoptab for this device
|
||||||
|
dev = (devoptab_t *) malloc(sizeof(devoptab_t) + strlen(name) + 1);
|
||||||
|
if (!dev) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the space allocated at the end of the devoptab for storing the device name
|
||||||
|
devname = (char*)(dev + 1);
|
||||||
|
strcpy(devname, name);
|
||||||
|
|
||||||
|
// create private data
|
||||||
|
fs_dev_private_t *priv = (fs_dev_private_t *)malloc(sizeof(fs_dev_private_t) + strlen(mount_path) + 1);
|
||||||
|
if(!priv) {
|
||||||
|
free(dev);
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
devpath = (char*)(priv+1);
|
||||||
|
strcpy(devpath, mount_path);
|
||||||
|
|
||||||
|
// setup private data
|
||||||
|
priv->mount_path = devpath;
|
||||||
|
priv->fsaFd = fsaFd;
|
||||||
|
priv->mounted = isMounted;
|
||||||
|
priv->pMutex = malloc(OS_MUTEX_SIZE);
|
||||||
|
|
||||||
|
if(!priv->pMutex) {
|
||||||
|
free(dev);
|
||||||
|
free(priv);
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSInitMutex(priv->pMutex);
|
||||||
|
|
||||||
|
// Setup the devoptab
|
||||||
|
memcpy(dev, &devops_fs, sizeof(devoptab_t));
|
||||||
|
dev->name = devname;
|
||||||
|
dev->deviceData = priv;
|
||||||
|
|
||||||
|
// Add the device to the devoptab table (if there is a free slot)
|
||||||
|
for (i = 3; i < STD_MAX; i++) {
|
||||||
|
if (devoptab_list[i] == devoptab_list[0]) {
|
||||||
|
devoptab_list[i] = dev;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// failure, free all memory
|
||||||
|
free(priv);
|
||||||
|
free(dev);
|
||||||
|
|
||||||
|
// If we reach here then there are no free slots in the devoptab table for this device
|
||||||
|
errno = EADDRNOTAVAIL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fs_dev_remove_device (const char *path)
|
||||||
|
{
|
||||||
|
const devoptab_t *devoptab = NULL;
|
||||||
|
char name[128] = {0};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Get the device name from the path
|
||||||
|
strncpy(name, path, 127);
|
||||||
|
strtok(name, ":/");
|
||||||
|
|
||||||
|
// Find and remove the specified device from the devoptab table
|
||||||
|
// NOTE: We do this manually due to a 'bug' in RemoveDevice
|
||||||
|
// which ignores names with suffixes and causes names
|
||||||
|
// like "ntfs" and "ntfs1" to be seen as equals
|
||||||
|
for (i = 3; i < STD_MAX; i++) {
|
||||||
|
devoptab = devoptab_list[i];
|
||||||
|
if (devoptab && devoptab->name) {
|
||||||
|
if (strcmp(name, devoptab->name) == 0) {
|
||||||
|
devoptab_list[i] = devoptab_list[0];
|
||||||
|
|
||||||
|
if(devoptab->deviceData)
|
||||||
|
{
|
||||||
|
fs_dev_private_t *priv = (fs_dev_private_t *)devoptab->deviceData;
|
||||||
|
|
||||||
|
if(priv->mounted)
|
||||||
|
IOSUHAX_FSA_Unmount(priv->fsaFd, priv->mount_path, 2);
|
||||||
|
|
||||||
|
if(priv->pMutex)
|
||||||
|
free(priv->pMutex);
|
||||||
|
free(devoptab->deviceData);
|
||||||
|
}
|
||||||
|
|
||||||
|
free((devoptab_t*)devoptab);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mount_fs(const char *virt_name, int fsaFd, const char *dev_path, const char *mount_path)
|
||||||
|
{
|
||||||
|
int isMounted = 0;
|
||||||
|
|
||||||
|
if(dev_path)
|
||||||
|
{
|
||||||
|
isMounted = 1;
|
||||||
|
|
||||||
|
int res = IOSUHAX_FSA_Mount(fsaFd, dev_path, mount_path, 2, 0, 0);
|
||||||
|
if(res != 0)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs_dev_add_device(virt_name, mount_path, fsaFd, isMounted);
|
||||||
|
}
|
||||||
|
|
||||||
|
int unmount_fs(const char *virt_name)
|
||||||
|
{
|
||||||
|
return fs_dev_remove_device(virt_name);
|
||||||
|
}
|
42
source/iosuhax_devoptab.h
Normal file
42
source/iosuhax_devoptab.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2015
|
||||||
|
* by Dimok
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied
|
||||||
|
* warranty. In no event will the authors be held liable for any
|
||||||
|
* damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any
|
||||||
|
* purpose, including commercial applications, and to alter it and
|
||||||
|
* redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you
|
||||||
|
* must not claim that you wrote the original software. If you use
|
||||||
|
* this software in a product, an acknowledgment in the product
|
||||||
|
* documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and
|
||||||
|
* must not be misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source
|
||||||
|
* distribution.
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef __IOSUHAX_DEVOPTAB_H_
|
||||||
|
#define __IOSUHAX_DEVOPTAB_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! virtual name example: sd or odd (for sd:/ or odd:/ access)
|
||||||
|
//! fsaFd: fd received by IOSUHAX_FSA_Open();
|
||||||
|
//! dev_path: (optional) if a device should be mounted to the mount_path. If NULL no IOSUHAX_FSA_Mount is not executed.
|
||||||
|
//! mount_path: path to map to virtual device name
|
||||||
|
int mount_fs(const char *virt_name, int fsaFd, const char *dev_path, const char *mount_path);
|
||||||
|
int unmount_fs(const char *virt_name);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __IOSUHAX_DEVOPTAB_H_
|
31
source/os_functions.h
Normal file
31
source/os_functions.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef __OS_FUNCTIONS_H_
|
||||||
|
#define __OS_FUNCTIONS_H_
|
||||||
|
|
||||||
|
#include <gctypes.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define OS_MUTEX_SIZE 44
|
||||||
|
|
||||||
|
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//! Mutex functions
|
||||||
|
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
extern void (* OSInitMutex)(void* mutex);
|
||||||
|
extern void (* OSLockMutex)(void* mutex);
|
||||||
|
extern void (* OSUnlockMutex)(void* mutex);
|
||||||
|
extern int (* OSTryLockMutex)(void* mutex);
|
||||||
|
|
||||||
|
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//! IOS function
|
||||||
|
//!----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
extern int (*IOS_Ioctl)(int fd, unsigned int request, void *input_buffer,unsigned int input_buffer_len, void *output_buffer, unsigned int output_buffer_len);
|
||||||
|
extern int (*IOS_Open)(char *path, unsigned int mode);
|
||||||
|
extern int (*IOS_Close)(int fd);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __OS_FUNCTIONS_H_
|
Loading…
Reference in New Issue
Block a user