├── .gitignore ├── .travis.yml ├── Makefile ├── README.md └── source ├── iosuhax.c ├── iosuhax.h ├── iosuhax_devoptab.c ├── iosuhax_devoptab.h ├── iosuhax_disc_interface.c ├── iosuhax_disc_interface.h └── os_functions.h /.gitignore: -------------------------------------------------------------------------------- 1 | /*.a 2 | /build 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | os: linux 4 | sudo: false 5 | dist: trusty 6 | 7 | env: 8 | global: 9 | - DEVKITPRO=/opt/devkitpro 10 | - DEVKITPPC=/opt/devkitpro/devkitPPC 11 | - PORTLIBREPOS=$HOME/portlibrepos 12 | 13 | cache: 14 | directories: 15 | - "$HOME/.local" 16 | - "$DEVKITPRO" 17 | 18 | addons: 19 | apt: 20 | packages: 21 | - p7zip-full 22 | 23 | before_install: 24 | - mkdir -p "${DEVKITPRO}" 25 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wget https://github.com/devkitPro/pacman/releases/download/devkitpro-pacman-1.0.1/devkitpro-pacman.deb -O /tmp/devkitpro-pacman.deb; fi 26 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo dpkg -i /tmp/devkitpro-pacman.deb; fi 27 | - yes | sudo dkp-pacman -Syu devkitPPC --needed 28 | 29 | script: 30 | - make && make install -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | # Clear the implicit built in rules 3 | #--------------------------------------------------------------------------------- 4 | .SUFFIXES: 5 | #--------------------------------------------------------------------------------- 6 | ifeq ($(strip $(DEVKITPPC)),) 7 | $(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") 8 | endif 9 | 10 | export PATH := $(DEVKITPPC)/bin:$(PORTLIBS)/bin:$(PATH) 11 | export PORTLIBS := $(DEVKITPRO)/portlibs/ppc 12 | 13 | PREFIX := powerpc-eabi- 14 | 15 | export AS := $(PREFIX)as 16 | export CC := $(PREFIX)gcc 17 | export CXX := $(PREFIX)g++ 18 | export AR := $(PREFIX)ar 19 | export OBJCOPY := $(PREFIX)objcopy 20 | 21 | include $(DEVKITPPC)/base_rules 22 | 23 | #--------------------------------------------------------------------------------- 24 | # BUILD is the directory where object files & intermediate files will be placed 25 | # SOURCES is a list of directories containing source code 26 | # INCLUDES is a list of directories containing extra header files 27 | #--------------------------------------------------------------------------------- 28 | BUILD := build 29 | SOURCES := source 30 | INCLUDES := iosuhax.h iosuhax_devoptab.h iosuhax_disc_interface.h 31 | LIBTARGET := libiosuhax.a 32 | 33 | #--------------------------------------------------------------------------------- 34 | # installation parameters 35 | #--------------------------------------------------------------------------------- 36 | LIBINSTALL := $(PORTLIBS)/lib 37 | HDRINSTALL := $(PORTLIBS)/include 38 | 39 | #--------------------------------------------------------------------------------- 40 | # options for code generation 41 | #--------------------------------------------------------------------------------- 42 | CFLAGS = -O2 $(DEF_FLAGS) -Wall -Wno-unused $(MACHDEP) $(INCLUDE) 43 | CXXFLAGS = $(CFLAGS) 44 | ASFLAGS := -g 45 | 46 | #--------------------------------------------------------------------------------- 47 | # any extra libraries we wish to link with the project 48 | #--------------------------------------------------------------------------------- 49 | LIBS := 50 | 51 | #--------------------------------------------------------------------------------- 52 | # list of directories containing libraries, this must be the top level containing 53 | # include and lib 54 | #--------------------------------------------------------------------------------- 55 | LIBDIRS := 56 | 57 | #--------------------------------------------------------------------------------- 58 | # no real need to edit anything past this point unless you need to add additional 59 | # rules for different file extensions 60 | #--------------------------------------------------------------------------------- 61 | ifneq ($(BUILD),$(notdir $(CURDIR))) 62 | #--------------------------------------------------------------------------------- 63 | 64 | export DEPSDIR := $(CURDIR)/$(BUILD) 65 | 66 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 67 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 68 | 69 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 70 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 71 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 72 | 73 | 74 | export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 75 | 76 | export INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 77 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 78 | -I$(CURDIR)/$(BUILD) -I$(LIBOGC_INC) \ 79 | -I$(PORTLIBS)/include 80 | 81 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ 82 | -L$(LIBOGC_LIB) -L$(PORTLIBS)/lib 83 | 84 | .PHONY: $(BUILD) clean 85 | 86 | #--------------------------------------------------------------------------------- 87 | $(BUILD): 88 | @[ -d $@ ] || mkdir -p $@ 89 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 90 | 91 | #--------------------------------------------------------------------------------- 92 | all: $(LIBTARGET) 93 | 94 | clean: 95 | @echo clean ... 96 | @rm -fr $(BUILD) $(LIBTARGET) 97 | 98 | install: $(LIBTARGET) 99 | @[ -d $(LIBINSTALL) ] || mkdir -p $(LIBINSTALL) 100 | @[ -d $(HDRINSTALL) ] || mkdir -p $(HDRINSTALL) 101 | cp $(foreach incl,$(INCLUDES),$(SOURCES)/$(incl)) $(HDRINSTALL) 102 | cp $(LIBTARGET) $(LIBINSTALL) 103 | 104 | wut: 105 | @[ -d $(BUILD) ] || mkdir -p $(BUILD) 106 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile DEF_FLAGS=-D__WUT__ 107 | 108 | #--------------------------------------------------------------------------------- 109 | else 110 | 111 | DEPENDS := $(OFILES:.o=.d) 112 | 113 | #--------------------------------------------------------------------------------- 114 | # main targets 115 | #--------------------------------------------------------------------------------- 116 | $(LIBTARGET): $(OFILES) 117 | @rm -f "../$(LIBTARGET)" 118 | @$(AR) rcs "../$(LIBTARGET)" $(OFILES) 119 | @echo built $(notdir $@) 120 | 121 | $(LIBDIR)/$(PLATFORM): 122 | mkdir -p ../$(LIBDIR)/$(PLATFORM) 123 | 124 | -include $(DEPENDS) 125 | 126 | #--------------------------------------------------------------------------------------- 127 | endif 128 | #--------------------------------------------------------------------------------------- 129 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/dimok789/libiosuhax.svg)](https://travis-ci.org/dimok789/libiosuhax) -------------------------------------------------------------------------------- /source/iosuhax.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2016 3 | * by Dimok 4 | * 5 | * This software is provided 'as-is', without any express or implied 6 | * warranty. In no event will the authors be held liable for any 7 | * damages arising from the use of this software. 8 | * 9 | * Permission is granted to anyone to use this software for any 10 | * purpose, including commercial applications, and to alter it and 11 | * redistribute it freely, subject to the following restrictions: 12 | * 13 | * 1. The origin of this software must not be misrepresented; you 14 | * must not claim that you wrote the original software. If you use 15 | * this software in a product, an acknowledgment in the product 16 | * documentation would be appreciated but is not required. 17 | * 18 | * 2. Altered source versions must be plainly marked as such, and 19 | * must not be misrepresented as being the original software. 20 | * 21 | * 3. This notice may not be removed or altered from any source 22 | * distribution. 23 | ***************************************************************************/ 24 | #include 25 | #include 26 | #include "os_functions.h" 27 | #include "iosuhax.h" 28 | 29 | #define IOSUHAX_MAGIC_WORD 0x4E696365 30 | 31 | #define IOCTL_MEM_WRITE 0x00 32 | #define IOCTL_MEM_READ 0x01 33 | #define IOCTL_SVC 0x02 34 | #define IOCTL_MEMCPY 0x04 35 | #define IOCTL_REPEATED_WRITE 0x05 36 | #define IOCTL_KERN_READ32 0x06 37 | #define IOCTL_KERN_WRITE32 0x07 38 | 39 | #define IOCTL_FSA_OPEN 0x40 40 | #define IOCTL_FSA_CLOSE 0x41 41 | #define IOCTL_FSA_MOUNT 0x42 42 | #define IOCTL_FSA_UNMOUNT 0x43 43 | #define IOCTL_FSA_GETDEVICEINFO 0x44 44 | #define IOCTL_FSA_OPENDIR 0x45 45 | #define IOCTL_FSA_READDIR 0x46 46 | #define IOCTL_FSA_CLOSEDIR 0x47 47 | #define IOCTL_FSA_MAKEDIR 0x48 48 | #define IOCTL_FSA_OPENFILE 0x49 49 | #define IOCTL_FSA_READFILE 0x4A 50 | #define IOCTL_FSA_WRITEFILE 0x4B 51 | #define IOCTL_FSA_STATFILE 0x4C 52 | #define IOCTL_FSA_CLOSEFILE 0x4D 53 | #define IOCTL_FSA_SETFILEPOS 0x4E 54 | #define IOCTL_FSA_GETSTAT 0x4F 55 | #define IOCTL_FSA_REMOVE 0x50 56 | #define IOCTL_FSA_REWINDDIR 0x51 57 | #define IOCTL_FSA_CHDIR 0x52 58 | #define IOCTL_FSA_RENAME 0x53 59 | #define IOCTL_FSA_RAW_OPEN 0x54 60 | #define IOCTL_FSA_RAW_READ 0x55 61 | #define IOCTL_FSA_RAW_WRITE 0x56 62 | #define IOCTL_FSA_RAW_CLOSE 0x57 63 | #define IOCTL_FSA_CHANGEMODE 0x58 64 | #define IOCTL_FSA_FLUSHVOLUME 0x59 65 | #define IOCTL_CHECK_IF_IOSUHAX 0x5B 66 | 67 | static int iosuhaxHandle = -1; 68 | 69 | #define ALIGN(align) __attribute__((aligned(align))) 70 | #define ROUNDUP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) 71 | 72 | int IOSUHAX_Open(const char *dev) 73 | { 74 | if(iosuhaxHandle >= 0) 75 | return iosuhaxHandle; 76 | 77 | iosuhaxHandle = IOS_Open((char*)(dev ? dev : "/dev/iosuhax"), 0); 78 | if(iosuhaxHandle >= 0 && dev) //make sure device is actually iosuhax 79 | { 80 | ALIGN(0x20) int res[0x20 >> 2]; 81 | *res = 0; 82 | 83 | IOS_Ioctl(iosuhaxHandle, IOCTL_CHECK_IF_IOSUHAX, (void*)0, 0, res, 4); 84 | if(*res != IOSUHAX_MAGIC_WORD) 85 | { 86 | IOS_Close(iosuhaxHandle); 87 | iosuhaxHandle = -1; 88 | } 89 | } 90 | 91 | return iosuhaxHandle; 92 | } 93 | 94 | int IOSUHAX_Close(void) 95 | { 96 | if(iosuhaxHandle < 0) 97 | return 0; 98 | 99 | int res = IOS_Close(iosuhaxHandle); 100 | iosuhaxHandle = -1; 101 | return res; 102 | } 103 | 104 | int IOSUHAX_memwrite(uint32_t address, const uint8_t * buffer, uint32_t size) 105 | { 106 | if(iosuhaxHandle < 0) 107 | return iosuhaxHandle; 108 | 109 | uint32_t *io_buf = (uint32_t*)memalign(0x20, ROUNDUP(size + 4, 0x20)); 110 | if(!io_buf) 111 | return -2; 112 | 113 | io_buf[0] = address; 114 | memcpy(io_buf + 1, buffer, size); 115 | 116 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_MEM_WRITE, io_buf, size + 4, 0, 0); 117 | 118 | free(io_buf); 119 | return res; 120 | } 121 | 122 | int IOSUHAX_memread(uint32_t address, uint8_t * out_buffer, uint32_t size) 123 | { 124 | if(iosuhaxHandle < 0) 125 | return iosuhaxHandle; 126 | 127 | ALIGN(0x20) int io_buf[0x20 >> 2]; 128 | io_buf[0] = address; 129 | 130 | void* tmp_buf = NULL; 131 | 132 | if(((uintptr_t)out_buffer & 0x1F) || (size & 0x1F)) 133 | { 134 | tmp_buf = (uint32_t*)memalign(0x20, ROUNDUP(size, 0x20)); 135 | if(!tmp_buf) 136 | return -2; 137 | } 138 | 139 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_MEM_READ, io_buf, sizeof(address), tmp_buf ? tmp_buf : out_buffer, size); 140 | 141 | if(res >= 0 && tmp_buf) 142 | memcpy(out_buffer, tmp_buf, size); 143 | 144 | free(tmp_buf); 145 | return res; 146 | } 147 | 148 | int IOSUHAX_memcpy(uint32_t dst, uint32_t src, uint32_t size) 149 | { 150 | if(iosuhaxHandle < 0) 151 | return iosuhaxHandle; 152 | 153 | ALIGN(0x20) uint32_t io_buf[0x20 >> 2]; 154 | io_buf[0] = dst; 155 | io_buf[1] = src; 156 | io_buf[2] = size; 157 | 158 | return IOS_Ioctl(iosuhaxHandle, IOCTL_MEMCPY, io_buf, 3 * sizeof(uint32_t), 0, 0); 159 | } 160 | 161 | int IOSUHAX_SVC(uint32_t svc_id, uint32_t * args, uint32_t arg_cnt) 162 | { 163 | if(iosuhaxHandle < 0) 164 | return iosuhaxHandle; 165 | 166 | ALIGN(0x20) uint32_t arguments[0x40 >> 2]; 167 | arguments[0] = svc_id; 168 | 169 | if(args && arg_cnt) 170 | { 171 | if(arg_cnt > 8) 172 | arg_cnt = 8; 173 | 174 | memcpy(arguments + 1, args, arg_cnt * 4); 175 | } 176 | 177 | ALIGN(0x20) int result[0x20 >> 2]; 178 | int ret = IOS_Ioctl(iosuhaxHandle, IOCTL_SVC, arguments, (1 + arg_cnt) * 4, result, 4); 179 | if(ret < 0) 180 | return ret; 181 | 182 | return *result; 183 | } 184 | 185 | int IOSUHAX_FSA_Open(void) 186 | { 187 | if(iosuhaxHandle < 0) 188 | return iosuhaxHandle; 189 | 190 | ALIGN(0x20) int io_buf[0x20 >> 2]; 191 | 192 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPEN, 0, 0, io_buf, sizeof(int)); 193 | if(res < 0) 194 | return res; 195 | 196 | return io_buf[0]; 197 | } 198 | 199 | int IOSUHAX_FSA_Close(int fsaFd) 200 | { 201 | if(iosuhaxHandle < 0) 202 | return iosuhaxHandle; 203 | 204 | ALIGN(0x20) int io_buf[0x20 >> 2]; 205 | io_buf[0] = fsaFd; 206 | 207 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSE, io_buf, sizeof(fsaFd), io_buf, sizeof(fsaFd)); 208 | if(res < 0) 209 | return res; 210 | 211 | return io_buf[0]; 212 | } 213 | 214 | 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) 215 | { 216 | if(iosuhaxHandle < 0) 217 | return iosuhaxHandle; 218 | 219 | const int input_cnt = 6; 220 | 221 | int io_buf_size = (sizeof(uint32_t) * input_cnt) + strlen(device_path) + strlen(volume_path) + arg_string_len + 3; 222 | 223 | ALIGN(0x20) int io_buf[ROUNDUP(io_buf_size, 0x20) >> 2]; 224 | memset(io_buf, 0, io_buf_size); 225 | 226 | io_buf[0] = fsaFd; 227 | io_buf[1] = sizeof(uint32_t) * input_cnt; 228 | io_buf[2] = io_buf[1] + strlen(device_path) + 1; 229 | io_buf[3] = flags; 230 | io_buf[4] = arg_string_len ? ( io_buf[2] + strlen(volume_path) + 1) : 0; 231 | io_buf[5] = arg_string_len; 232 | 233 | strcpy(((char*)io_buf) + io_buf[1], device_path); 234 | strcpy(((char*)io_buf) + io_buf[2], volume_path); 235 | 236 | if(arg_string_len) 237 | memcpy(((char*)io_buf) + io_buf[4], arg_string, arg_string_len); 238 | 239 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_MOUNT, io_buf, io_buf_size, io_buf, 4); 240 | if(res < 0) 241 | return res; 242 | 243 | return io_buf[0]; 244 | } 245 | 246 | int IOSUHAX_FSA_Unmount(int fsaFd, const char* path, uint32_t flags) 247 | { 248 | if(iosuhaxHandle < 0) 249 | return iosuhaxHandle; 250 | 251 | const int input_cnt = 3; 252 | 253 | int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; 254 | 255 | ALIGN(0x20) int io_buf[ROUNDUP(io_buf_size, 0x20) >> 2]; 256 | 257 | io_buf[0] = fsaFd; 258 | io_buf[1] = sizeof(uint32_t) * input_cnt; 259 | io_buf[2] = flags; 260 | strcpy(((char*)io_buf) + io_buf[1], path); 261 | 262 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_UNMOUNT, io_buf, io_buf_size, io_buf, 4); 263 | if(res < 0) 264 | return res; 265 | 266 | return io_buf[0]; 267 | } 268 | 269 | int IOSUHAX_FSA_FlushVolume(int fsaFd, const char *volume_path) 270 | { 271 | if(iosuhaxHandle < 0) 272 | return iosuhaxHandle; 273 | 274 | const int input_cnt = 2; 275 | 276 | int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(volume_path) + 1; 277 | 278 | ALIGN(0x20) int io_buf[ROUNDUP(io_buf_size, 0x20) >> 2]; 279 | 280 | io_buf[0] = fsaFd; 281 | io_buf[1] = sizeof(uint32_t) * input_cnt; 282 | strcpy(((char*)io_buf) + io_buf[1], volume_path); 283 | 284 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_FLUSHVOLUME, io_buf, io_buf_size, io_buf, 4); 285 | if(res < 0) 286 | return res; 287 | 288 | return io_buf[0]; 289 | } 290 | 291 | int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char* device_path, int type, uint32_t* out_data) 292 | { 293 | if(iosuhaxHandle < 0) 294 | return iosuhaxHandle; 295 | 296 | const int input_cnt = 3; 297 | 298 | int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(device_path) + 1; 299 | 300 | uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); 301 | if(!io_buf) 302 | return -2; 303 | 304 | io_buf[0] = fsaFd; 305 | io_buf[1] = sizeof(uint32_t) * input_cnt; 306 | io_buf[2] = type; 307 | strcpy(((char*)io_buf) + io_buf[1], device_path); 308 | 309 | uint32_t out_buf[1 + 0x64 / 4]; 310 | 311 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETDEVICEINFO, io_buf, io_buf_size, out_buf, sizeof(out_buf)); 312 | if(res < 0) 313 | { 314 | free(io_buf); 315 | return res; 316 | } 317 | 318 | memcpy(out_data, out_buf + 1, 0x64); 319 | free(io_buf); 320 | return out_buf[0]; 321 | } 322 | 323 | int IOSUHAX_FSA_MakeDir(int fsaFd, const char* path, uint32_t flags) 324 | { 325 | if(iosuhaxHandle < 0) 326 | return iosuhaxHandle; 327 | 328 | const int input_cnt = 3; 329 | 330 | int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; 331 | 332 | uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); 333 | if(!io_buf) 334 | return -2; 335 | 336 | io_buf[0] = fsaFd; 337 | io_buf[1] = sizeof(uint32_t) * input_cnt; 338 | io_buf[2] = flags; 339 | strcpy(((char*)io_buf) + io_buf[1], path); 340 | 341 | int result; 342 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_MAKEDIR, io_buf, io_buf_size, &result, sizeof(result)); 343 | if(res < 0) 344 | { 345 | free(io_buf); 346 | return res; 347 | } 348 | 349 | free(io_buf); 350 | return result; 351 | } 352 | 353 | int IOSUHAX_FSA_OpenDir(int fsaFd, const char* path, int* outHandle) 354 | { 355 | if(iosuhaxHandle < 0) 356 | return iosuhaxHandle; 357 | 358 | const int input_cnt = 2; 359 | 360 | int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; 361 | 362 | uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); 363 | if(!io_buf) 364 | return -2; 365 | 366 | io_buf[0] = fsaFd; 367 | io_buf[1] = sizeof(uint32_t) * input_cnt; 368 | strcpy(((char*)io_buf) + io_buf[1], path); 369 | 370 | int result_vec[2]; 371 | 372 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPENDIR, io_buf, io_buf_size, result_vec, sizeof(result_vec)); 373 | if(res < 0) 374 | { 375 | free(io_buf); 376 | return res; 377 | } 378 | 379 | *outHandle = result_vec[1]; 380 | free(io_buf); 381 | return result_vec[0]; 382 | } 383 | 384 | int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, directoryEntry_s* out_data) 385 | { 386 | if(iosuhaxHandle < 0) 387 | return iosuhaxHandle; 388 | 389 | const int input_cnt = 2; 390 | 391 | int io_buf_size = sizeof(uint32_t) * input_cnt; 392 | 393 | uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); 394 | if(!io_buf) 395 | return -2; 396 | 397 | io_buf[0] = fsaFd; 398 | io_buf[1] = handle; 399 | 400 | int result_vec_size = 4 + sizeof(directoryEntry_s); 401 | uint8_t *result_vec = (uint8_t*) memalign(0x20, result_vec_size); 402 | if(!result_vec) 403 | { 404 | free(io_buf); 405 | return -2; 406 | } 407 | 408 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_READDIR, io_buf, io_buf_size, result_vec, result_vec_size); 409 | if(res < 0) 410 | { 411 | free(result_vec); 412 | free(io_buf); 413 | return res; 414 | } 415 | 416 | int result = *(int*)result_vec; 417 | memcpy(out_data, result_vec + 4, sizeof(directoryEntry_s)); 418 | free(io_buf); 419 | free(result_vec); 420 | return result; 421 | } 422 | 423 | int IOSUHAX_FSA_RewindDir(int fsaFd, int dirHandle) 424 | { 425 | if(iosuhaxHandle < 0) 426 | return iosuhaxHandle; 427 | 428 | const int input_cnt = 2; 429 | 430 | int io_buf_size = sizeof(uint32_t) * input_cnt; 431 | 432 | uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); 433 | if(!io_buf) 434 | return -2; 435 | 436 | io_buf[0] = fsaFd; 437 | io_buf[1] = dirHandle; 438 | 439 | int result; 440 | 441 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_REWINDDIR, io_buf, io_buf_size, &result, sizeof(result)); 442 | if(res < 0) 443 | { 444 | free(io_buf); 445 | return res; 446 | } 447 | 448 | free(io_buf); 449 | return result; 450 | } 451 | 452 | int IOSUHAX_FSA_CloseDir(int fsaFd, int handle) 453 | { 454 | if(iosuhaxHandle < 0) 455 | return iosuhaxHandle; 456 | 457 | const int input_cnt = 2; 458 | 459 | int io_buf_size = sizeof(uint32_t) * input_cnt; 460 | 461 | uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); 462 | if(!io_buf) 463 | return -2; 464 | 465 | io_buf[0] = fsaFd; 466 | io_buf[1] = handle; 467 | 468 | int result; 469 | 470 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSEDIR, io_buf, io_buf_size, &result, sizeof(result)); 471 | if(res < 0) 472 | { 473 | free(io_buf); 474 | return res; 475 | } 476 | 477 | free(io_buf); 478 | return result; 479 | } 480 | 481 | int IOSUHAX_FSA_ChangeDir(int fsaFd, const char *path) 482 | { 483 | if(iosuhaxHandle < 0) 484 | return iosuhaxHandle; 485 | 486 | const int input_cnt = 2; 487 | 488 | int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; 489 | 490 | uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); 491 | if(!io_buf) 492 | return -2; 493 | 494 | io_buf[0] = fsaFd; 495 | io_buf[1] = sizeof(uint32_t) * input_cnt; 496 | strcpy(((char*)io_buf) + io_buf[1], path); 497 | 498 | int result; 499 | 500 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CHDIR, io_buf, io_buf_size, &result, sizeof(result)); 501 | if(res < 0) 502 | { 503 | free(io_buf); 504 | return res; 505 | } 506 | 507 | free(io_buf); 508 | return result; 509 | } 510 | 511 | int IOSUHAX_FSA_OpenFile(int fsaFd, const char* path, const char* mode, int* outHandle) 512 | { 513 | if(iosuhaxHandle < 0) 514 | return iosuhaxHandle; 515 | 516 | const int input_cnt = 3; 517 | 518 | int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + strlen(mode) + 2; 519 | 520 | uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); 521 | if(!io_buf) 522 | return -2; 523 | 524 | io_buf[0] = fsaFd; 525 | io_buf[1] = sizeof(uint32_t) * input_cnt; 526 | io_buf[2] = io_buf[1] + strlen(path) + 1; 527 | strcpy(((char*)io_buf) + io_buf[1], path); 528 | strcpy(((char*)io_buf) + io_buf[2], mode); 529 | 530 | int result_vec[2]; 531 | 532 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPENFILE, io_buf, io_buf_size, result_vec, sizeof(result_vec)); 533 | if(res < 0) 534 | { 535 | free(io_buf); 536 | return res; 537 | } 538 | 539 | *outHandle = result_vec[1]; 540 | free(io_buf); 541 | return result_vec[0]; 542 | } 543 | 544 | int IOSUHAX_FSA_ReadFile(int fsaFd, void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags) 545 | { 546 | if(iosuhaxHandle < 0) 547 | return iosuhaxHandle; 548 | 549 | const int input_cnt = 5; 550 | 551 | int io_buf_size = sizeof(uint32_t) * input_cnt; 552 | 553 | uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); 554 | if(!io_buf) 555 | return -2; 556 | 557 | io_buf[0] = fsaFd; 558 | io_buf[1] = size; 559 | io_buf[2] = cnt; 560 | io_buf[3] = fileHandle; 561 | io_buf[4] = flags; 562 | 563 | int out_buf_size = ((size * cnt + 0x40) + 0x3F) & ~0x3F; 564 | 565 | uint32_t *out_buffer = (uint32_t*)memalign(0x40, out_buf_size); 566 | if(!out_buffer) 567 | { 568 | free(io_buf); 569 | return -2; 570 | } 571 | 572 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_READFILE, io_buf, io_buf_size, out_buffer, out_buf_size); 573 | if(res < 0) 574 | { 575 | free(out_buffer); 576 | free(io_buf); 577 | return res; 578 | } 579 | 580 | //! data is put to offset 0x40 to align the buffer output 581 | memcpy(data, ((uint8_t*)out_buffer) + 0x40, size * cnt); 582 | 583 | int result = out_buffer[0]; 584 | 585 | free(out_buffer); 586 | free(io_buf); 587 | return result; 588 | } 589 | 590 | int IOSUHAX_FSA_WriteFile(int fsaFd, const void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags) 591 | { 592 | if(iosuhaxHandle < 0) 593 | return iosuhaxHandle; 594 | 595 | const int input_cnt = 5; 596 | 597 | int io_buf_size = ((sizeof(uint32_t) * input_cnt + size * cnt + 0x40) + 0x3F) & ~0x3F; 598 | 599 | uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); 600 | if(!io_buf) 601 | return -2; 602 | 603 | io_buf[0] = fsaFd; 604 | io_buf[1] = size; 605 | io_buf[2] = cnt; 606 | io_buf[3] = fileHandle; 607 | io_buf[4] = flags; 608 | 609 | //! data is put to offset 0x40 to align the buffer input 610 | memcpy(((uint8_t*)io_buf) + 0x40, data, size * cnt); 611 | 612 | int result; 613 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_WRITEFILE, io_buf, io_buf_size, &result, sizeof(result)); 614 | if(res < 0) 615 | { 616 | free(io_buf); 617 | return res; 618 | } 619 | free(io_buf); 620 | return result; 621 | } 622 | 623 | int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, fileStat_s* out_data) 624 | { 625 | if(iosuhaxHandle < 0) 626 | return iosuhaxHandle; 627 | 628 | const int input_cnt = 2; 629 | 630 | int io_buf_size = sizeof(uint32_t) * input_cnt; 631 | 632 | uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); 633 | if(!io_buf) 634 | return -2; 635 | 636 | io_buf[0] = fsaFd; 637 | io_buf[1] = fileHandle; 638 | 639 | int out_buf_size = 4 + sizeof(fileStat_s); 640 | uint32_t *out_buffer = (uint32_t*)memalign(0x20, out_buf_size); 641 | if(!out_buffer) 642 | { 643 | free(io_buf); 644 | return -2; 645 | } 646 | 647 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_STATFILE, io_buf, io_buf_size, out_buffer, out_buf_size); 648 | if(res < 0) 649 | { 650 | free(io_buf); 651 | free(out_buffer); 652 | return res; 653 | } 654 | 655 | int result = out_buffer[0]; 656 | memcpy(out_data, out_buffer + 1, sizeof(fileStat_s)); 657 | 658 | free(io_buf); 659 | free(out_buffer); 660 | return result; 661 | } 662 | 663 | int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle) 664 | { 665 | if(iosuhaxHandle < 0) 666 | return iosuhaxHandle; 667 | 668 | const int input_cnt = 2; 669 | 670 | int io_buf_size = sizeof(uint32_t) * input_cnt; 671 | 672 | uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); 673 | if(!io_buf) 674 | return -2; 675 | 676 | io_buf[0] = fsaFd; 677 | io_buf[1] = fileHandle; 678 | 679 | int result; 680 | 681 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSEFILE, io_buf, io_buf_size, &result, sizeof(result)); 682 | if(res < 0) 683 | { 684 | free(io_buf); 685 | return res; 686 | } 687 | 688 | free(io_buf); 689 | return result; 690 | } 691 | 692 | int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position) 693 | { 694 | if(iosuhaxHandle < 0) 695 | return iosuhaxHandle; 696 | 697 | const int input_cnt = 3; 698 | 699 | int io_buf_size = sizeof(uint32_t) * input_cnt; 700 | 701 | uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); 702 | if(!io_buf) 703 | return -2; 704 | 705 | io_buf[0] = fsaFd; 706 | io_buf[1] = fileHandle; 707 | io_buf[2] = position; 708 | 709 | int result; 710 | 711 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_SETFILEPOS, io_buf, io_buf_size, &result, sizeof(result)); 712 | if(res < 0) 713 | { 714 | free(io_buf); 715 | return res; 716 | } 717 | 718 | free(io_buf); 719 | return result; 720 | } 721 | 722 | int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, fileStat_s* out_data) 723 | { 724 | if(iosuhaxHandle < 0) 725 | return iosuhaxHandle; 726 | 727 | const int input_cnt = 2; 728 | 729 | int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; 730 | 731 | uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); 732 | if(!io_buf) 733 | return -2; 734 | 735 | io_buf[0] = fsaFd; 736 | io_buf[1] = sizeof(uint32_t) * input_cnt; 737 | strcpy(((char*)io_buf) + io_buf[1], path); 738 | 739 | int out_buf_size = 4 + sizeof(fileStat_s); 740 | uint32_t *out_buffer = (uint32_t*)memalign(0x20, out_buf_size); 741 | if(!out_buffer) 742 | { 743 | free(io_buf); 744 | return -2; 745 | } 746 | 747 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETSTAT, io_buf, io_buf_size, out_buffer, out_buf_size); 748 | if(res < 0) 749 | { 750 | free(io_buf); 751 | free(out_buffer); 752 | return res; 753 | } 754 | 755 | int result = out_buffer[0]; 756 | memcpy(out_data, out_buffer + 1, sizeof(fileStat_s)); 757 | 758 | free(io_buf); 759 | free(out_buffer); 760 | return result; 761 | } 762 | 763 | int IOSUHAX_FSA_Remove(int fsaFd, const char *path) 764 | { 765 | if(iosuhaxHandle < 0) 766 | return iosuhaxHandle; 767 | 768 | const int input_cnt = 2; 769 | 770 | int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; 771 | 772 | uint32_t *io_buf = (uint32_t*)memalign(0x20, ROUNDUP(io_buf_size, 0x20)); 773 | if(!io_buf) 774 | return -2; 775 | 776 | io_buf[0] = fsaFd; 777 | io_buf[1] = sizeof(uint32_t) * input_cnt; 778 | strcpy(((char*)io_buf) + io_buf[1], path); 779 | 780 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_REMOVE, io_buf, io_buf_size, io_buf, 4); 781 | if(res >= 0) 782 | res = io_buf[0]; 783 | 784 | free(io_buf); 785 | return res; 786 | } 787 | 788 | int IOSUHAX_FSA_ChangeMode(int fsaFd, const char* path, int mode) 789 | { 790 | if(iosuhaxHandle < 0) 791 | return iosuhaxHandle; 792 | 793 | const int input_cnt = 3; 794 | 795 | int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; 796 | 797 | ALIGN(0x20) uint32_t io_buf[ROUNDUP(io_buf_size, 0x20) >> 2]; 798 | 799 | io_buf[0] = fsaFd; 800 | io_buf[1] = sizeof(uint32_t) * input_cnt; 801 | io_buf[2] = mode; 802 | strcpy(((char*)io_buf) + io_buf[1], path); 803 | 804 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CHANGEMODE, io_buf, io_buf_size, io_buf, 4); 805 | if(res < 0) 806 | return res; 807 | 808 | return io_buf[0]; 809 | } 810 | 811 | int IOSUHAX_FSA_RawOpen(int fsaFd, const char* device_path, int* outHandle) 812 | { 813 | if(iosuhaxHandle < 0) 814 | return iosuhaxHandle; 815 | 816 | const int input_cnt = 2; 817 | 818 | int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(device_path) + 1; 819 | 820 | ALIGN(0x20) uint32_t io_buf[ROUNDUP(io_buf_size, 0x20) >> 2]; 821 | 822 | io_buf[0] = fsaFd; 823 | io_buf[1] = sizeof(uint32_t) * input_cnt; 824 | strcpy(((char*)io_buf) + io_buf[1], device_path); 825 | 826 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_OPEN, io_buf, io_buf_size, io_buf, 2 * sizeof(int)); 827 | if(res < 0) 828 | return res; 829 | 830 | if(outHandle) 831 | *outHandle = io_buf[1]; 832 | 833 | return io_buf[0]; 834 | } 835 | 836 | int IOSUHAX_FSA_RawRead(int fsaFd, void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle) 837 | { 838 | if(iosuhaxHandle < 0) 839 | return iosuhaxHandle; 840 | 841 | const int input_cnt = 6; 842 | 843 | int io_buf_size = 0x40 + block_size * block_cnt; 844 | uint32_t *io_buf = (uint32_t*)memalign(0x40, ROUNDUP(io_buf_size, 0x40)); 845 | 846 | if(!io_buf) 847 | return -2; 848 | 849 | io_buf[0] = fsaFd; 850 | io_buf[1] = block_size; 851 | io_buf[2] = block_cnt; 852 | io_buf[3] = (sector_offset >> 32) & 0xFFFFFFFF; 853 | io_buf[4] = sector_offset & 0xFFFFFFFF; 854 | io_buf[5] = device_handle; 855 | 856 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_READ, io_buf, sizeof(uint32_t) * input_cnt, io_buf, io_buf_size); 857 | if(res >= 0) 858 | { 859 | //! data is put to offset 0x40 to align the buffer output 860 | memcpy(data, ((uint8_t*)io_buf) + 0x40, block_size * block_cnt); 861 | 862 | res = io_buf[0]; 863 | } 864 | 865 | free(io_buf); 866 | return res; 867 | } 868 | 869 | int IOSUHAX_FSA_RawWrite(int fsaFd, const void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle) 870 | { 871 | if(iosuhaxHandle < 0) 872 | return iosuhaxHandle; 873 | 874 | int io_buf_size = ROUNDUP(0x40 + block_size * block_cnt, 0x40); 875 | 876 | uint32_t *io_buf = (uint32_t*)memalign(0x40, io_buf_size); 877 | if(!io_buf) 878 | return -2; 879 | 880 | io_buf[0] = fsaFd; 881 | io_buf[1] = block_size; 882 | io_buf[2] = block_cnt; 883 | io_buf[3] = (sector_offset >> 32) & 0xFFFFFFFF; 884 | io_buf[4] = sector_offset & 0xFFFFFFFF; 885 | io_buf[5] = device_handle; 886 | 887 | //! data is put to offset 0x40 to align the buffer input 888 | memcpy(((uint8_t*)io_buf) + 0x40, data, block_size * block_cnt); 889 | 890 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_WRITE, io_buf, io_buf_size, io_buf, 4); 891 | if(res >= 0) 892 | res = io_buf[0]; 893 | 894 | free(io_buf); 895 | return res; 896 | } 897 | 898 | 899 | int IOSUHAX_FSA_RawClose(int fsaFd, int device_handle) 900 | { 901 | if(iosuhaxHandle < 0) 902 | return iosuhaxHandle; 903 | 904 | const int input_cnt = 2; 905 | 906 | int io_buf_size = sizeof(uint32_t) * input_cnt; 907 | 908 | ALIGN(0x20) uint32_t io_buf[ROUNDUP(io_buf_size, 0x20) >> 2]; 909 | 910 | io_buf[0] = fsaFd; 911 | io_buf[1] = device_handle; 912 | 913 | int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_CLOSE, io_buf, io_buf_size, io_buf, 4); 914 | if(res < 0) 915 | return res; 916 | 917 | return io_buf[0]; 918 | } 919 | -------------------------------------------------------------------------------- /source/iosuhax.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2016 3 | * by Dimok 4 | * 5 | * This software is provided 'as-is', without any express or implied 6 | * warranty. In no event will the authors be held liable for any 7 | * damages arising from the use of this software. 8 | * 9 | * Permission is granted to anyone to use this software for any 10 | * purpose, including commercial applications, and to alter it and 11 | * redistribute it freely, subject to the following restrictions: 12 | * 13 | * 1. The origin of this software must not be misrepresented; you 14 | * must not claim that you wrote the original software. If you use 15 | * this software in a product, an acknowledgment in the product 16 | * documentation would be appreciated but is not required. 17 | * 18 | * 2. Altered source versions must be plainly marked as such, and 19 | * must not be misrepresented as being the original software. 20 | * 21 | * 3. This notice may not be removed or altered from any source 22 | * distribution. 23 | ***************************************************************************/ 24 | #ifndef _LIB_IOSUHAX_H_ 25 | #define _LIB_IOSUHAX_H_ 26 | 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | #define IOS_ERROR_UNKNOWN_VALUE 0xFFFFFFD6 34 | #define IOS_ERROR_INVALID_ARG 0xFFFFFFE3 35 | #define IOS_ERROR_INVALID_SIZE 0xFFFFFFE9 36 | #define IOS_ERROR_UNKNOWN 0xFFFFFFF7 37 | #define IOS_ERROR_NOEXISTS 0xFFFFFFFA 38 | 39 | typedef struct 40 | { 41 | uint32_t flag; 42 | uint32_t permission; 43 | uint32_t owner_id; 44 | uint32_t group_id; 45 | uint32_t size; // size in bytes 46 | uint32_t physsize; // physical size on disk in bytes 47 | uint32_t unk[3]; 48 | uint32_t id; 49 | uint32_t ctime; 50 | uint32_t mtime; 51 | uint32_t unk2[0x0D]; 52 | }fileStat_s; 53 | 54 | typedef struct 55 | { 56 | fileStat_s stat; 57 | char name[0x100]; 58 | }directoryEntry_s; 59 | 60 | #define DIR_ENTRY_IS_DIRECTORY 0x80000000 61 | 62 | #define FSA_MOUNTFLAGS_BINDMOUNT (1 << 0) 63 | #define FSA_MOUNTFLAGS_GLOBAL (1 << 1) 64 | 65 | int IOSUHAX_Open(const char *dev); // if dev == NULL the default path /dev/iosuhax will be used 66 | int IOSUHAX_Close(void); 67 | 68 | int IOSUHAX_memwrite(uint32_t address, const uint8_t * buffer, uint32_t size); // IOSU external input 69 | int IOSUHAX_memread(uint32_t address, uint8_t * out_buffer, uint32_t size); // IOSU external output 70 | int IOSUHAX_memcpy(uint32_t dst, uint32_t src, uint32_t size); // IOSU internal memcpy only 71 | 72 | int IOSUHAX_SVC(uint32_t svc_id, uint32_t * args, uint32_t arg_cnt); 73 | 74 | int IOSUHAX_FSA_Open(); 75 | int IOSUHAX_FSA_Close(int fsaFd); 76 | 77 | 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); 78 | int IOSUHAX_FSA_Unmount(int fsaFd, const char* path, uint32_t flags); 79 | int IOSUHAX_FSA_FlushVolume(int fsaFd, const char* volume_path); 80 | 81 | int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char* device_path, int type, uint32_t* out_data); 82 | 83 | int IOSUHAX_FSA_MakeDir(int fsaFd, const char* path, uint32_t flags); 84 | int IOSUHAX_FSA_OpenDir(int fsaFd, const char* path, int* outHandle); 85 | int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, directoryEntry_s* out_data); 86 | int IOSUHAX_FSA_RewindDir(int fsaFd, int dirHandle); 87 | int IOSUHAX_FSA_CloseDir(int fsaFd, int handle); 88 | int IOSUHAX_FSA_ChangeDir(int fsaFd, const char *path); 89 | 90 | int IOSUHAX_FSA_OpenFile(int fsaFd, const char* path, const char* mode, int* outHandle); 91 | int IOSUHAX_FSA_ReadFile(int fsaFd, void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags); 92 | int IOSUHAX_FSA_WriteFile(int fsaFd, const void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags); 93 | int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, fileStat_s* out_data); 94 | int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle); 95 | int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position); 96 | int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, fileStat_s* out_data); 97 | int IOSUHAX_FSA_Remove(int fsaFd, const char *path); 98 | int IOSUHAX_FSA_ChangeMode(int fsaFd, const char* path, int mode); 99 | 100 | int IOSUHAX_FSA_RawOpen(int fsaFd, const char* device_path, int* outHandle); 101 | int IOSUHAX_FSA_RawRead(int fsaFd, void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle); 102 | int IOSUHAX_FSA_RawWrite(int fsaFd, const void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle); 103 | int IOSUHAX_FSA_RawClose(int fsaFd, int device_handle); 104 | 105 | #ifdef __cplusplus 106 | } 107 | #endif 108 | 109 | #endif 110 | -------------------------------------------------------------------------------- /source/iosuhax_devoptab.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2015 3 | * by Dimok 4 | * 5 | * This software is provided 'as-is', without any express or implied 6 | * warranty. In no event will the authors be held liable for any 7 | * damages arising from the use of this software. 8 | * 9 | * Permission is granted to anyone to use this software for any 10 | * purpose, including commercial applications, and to alter it and 11 | * redistribute it freely, subject to the following restrictions: 12 | * 13 | * 1. The origin of this software must not be misrepresented; you 14 | * must not claim that you wrote the original software. If you use 15 | * this software in a product, an acknowledgment in the product 16 | * documentation would be appreciated but is not required. 17 | * 18 | * 2. Altered source versions must be plainly marked as such, and 19 | * must not be misrepresented as being the original software. 20 | * 21 | * 3. This notice may not be removed or altered from any source 22 | * distribution. 23 | ***************************************************************************/ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "os_functions.h" 35 | #include "iosuhax.h" 36 | 37 | typedef struct _fs_dev_private_t { 38 | char *mount_path; 39 | int fsaFd; 40 | int mounted; 41 | void *pMutex; 42 | } fs_dev_private_t; 43 | 44 | typedef struct _fs_dev_file_state_t { 45 | fs_dev_private_t *dev; 46 | int fd; /* File descriptor */ 47 | int flags; /* Opening flags */ 48 | int read; /* True if allowed to read from file */ 49 | int write; /* True if allowed to write to file */ 50 | int append; /* True if allowed to append to file */ 51 | uint32_t pos; /* Current position within the file (in bytes) */ 52 | uint32_t len; /* Total length of the file (in bytes) */ 53 | struct _fs_dev_file_state_t *prevOpenFile; /* The previous entry in a double-linked FILO list of open files */ 54 | struct _fs_dev_file_state_t *nextOpenFile; /* The next entry in a double-linked FILO list of open files */ 55 | } fs_dev_file_state_t; 56 | 57 | typedef struct _fs_dev_dir_entry_t { 58 | fs_dev_private_t *dev; 59 | int dirHandle; 60 | } fs_dev_dir_entry_t; 61 | 62 | static fs_dev_private_t *fs_dev_get_device_data(const char *path) 63 | { 64 | const devoptab_t *devoptab = NULL; 65 | char name[128] = {0}; 66 | int i; 67 | 68 | // Get the device name from the path 69 | strncpy(name, path, 127); 70 | strtok(name, ":/"); 71 | 72 | // Search the devoptab table for the specified device name 73 | // NOTE: We do this manually due to a 'bug' in GetDeviceOpTab 74 | // which ignores names with suffixes and causes names 75 | // like "ntfs" and "ntfs1" to be seen as equals 76 | for (i = 3; i < STD_MAX; i++) { 77 | devoptab = devoptab_list[i]; 78 | if (devoptab && devoptab->name) { 79 | if (strcmp(name, devoptab->name) == 0) { 80 | return (fs_dev_private_t *)devoptab->deviceData; 81 | } 82 | } 83 | } 84 | 85 | return NULL; 86 | } 87 | 88 | static char *fs_dev_real_path (const char *path, fs_dev_private_t *dev) 89 | { 90 | // Sanity check 91 | if (!path) 92 | return NULL; 93 | 94 | // Move the path pointer to the start of the actual path 95 | if (strchr(path, ':') != NULL) { 96 | path = strchr(path, ':') + 1; 97 | } 98 | 99 | int mount_len = strlen(dev->mount_path); 100 | 101 | char *new_name = (char*)malloc(mount_len + strlen(path) + 1); 102 | if(new_name) { 103 | strcpy(new_name, dev->mount_path); 104 | strcpy(new_name + mount_len, path); 105 | return new_name; 106 | } 107 | return new_name; 108 | } 109 | 110 | static int fs_dev_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) 111 | { 112 | fs_dev_private_t *dev = fs_dev_get_device_data(path); 113 | if(!dev) { 114 | r->_errno = ENODEV; 115 | return -1; 116 | } 117 | 118 | fs_dev_file_state_t *file = (fs_dev_file_state_t *)fileStruct; 119 | 120 | file->dev = dev; 121 | // Determine which mode the file is opened for 122 | file->flags = flags; 123 | 124 | const char *mode_str; 125 | 126 | if ((flags & 0x03) == O_RDONLY) { 127 | file->read = 1; 128 | file->write = 0; 129 | file->append = 0; 130 | mode_str = "r"; 131 | } else if ((flags & 0x03) == O_WRONLY) { 132 | file->read = 0; 133 | file->write = 1; 134 | file->append = (flags & O_APPEND); 135 | mode_str = file->append ? "a" : "w"; 136 | } else if ((flags & 0x03) == O_RDWR) { 137 | file->read = 1; 138 | file->write = 1; 139 | file->append = (flags & O_APPEND); 140 | mode_str = file->append ? "a+" : "r+"; 141 | } else { 142 | r->_errno = EACCES; 143 | return -1; 144 | } 145 | 146 | int fd = -1; 147 | 148 | OSLockMutex(dev->pMutex); 149 | 150 | char *real_path = fs_dev_real_path(path, dev); 151 | if(!path) { 152 | r->_errno = ENOMEM; 153 | OSUnlockMutex(dev->pMutex); 154 | return -1; 155 | } 156 | 157 | int result = IOSUHAX_FSA_OpenFile(dev->fsaFd, real_path, mode_str, &fd); 158 | 159 | free(real_path); 160 | 161 | if(result == 0) 162 | { 163 | fileStat_s stats; 164 | result = IOSUHAX_FSA_StatFile(dev->fsaFd, fd, &stats); 165 | if(result != 0) { 166 | IOSUHAX_FSA_CloseFile(dev->fsaFd, fd); 167 | r->_errno = result; 168 | OSUnlockMutex(dev->pMutex); 169 | return -1; 170 | } 171 | file->fd = fd; 172 | file->pos = 0; 173 | file->len = stats.size; 174 | OSUnlockMutex(dev->pMutex); 175 | return (int)file; 176 | } 177 | 178 | r->_errno = result; 179 | OSUnlockMutex(dev->pMutex); 180 | return -1; 181 | } 182 | 183 | 184 | static int fs_dev_close_r (struct _reent *r, void *fd) 185 | { 186 | fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; 187 | if(!file->dev) { 188 | r->_errno = ENODEV; 189 | return -1; 190 | } 191 | 192 | OSLockMutex(file->dev->pMutex); 193 | 194 | int result = IOSUHAX_FSA_CloseFile(file->dev->fsaFd, file->fd); 195 | 196 | OSUnlockMutex(file->dev->pMutex); 197 | 198 | if(result < 0) 199 | { 200 | r->_errno = result; 201 | return -1; 202 | } 203 | return 0; 204 | } 205 | 206 | static off_t fs_dev_seek_r (struct _reent *r, void *fd, off_t pos, int dir) 207 | { 208 | fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; 209 | if(!file->dev) { 210 | r->_errno = ENODEV; 211 | return 0; 212 | } 213 | 214 | OSLockMutex(file->dev->pMutex); 215 | 216 | switch(dir) 217 | { 218 | case SEEK_SET: 219 | file->pos = pos; 220 | break; 221 | case SEEK_CUR: 222 | file->pos += pos; 223 | break; 224 | case SEEK_END: 225 | file->pos = file->len + pos; 226 | break; 227 | default: 228 | r->_errno = EINVAL; 229 | return -1; 230 | } 231 | 232 | int result = IOSUHAX_FSA_SetFilePos(file->dev->fsaFd, file->fd, file->pos); 233 | 234 | OSUnlockMutex(file->dev->pMutex); 235 | 236 | if(result == 0) 237 | { 238 | return file->pos; 239 | } 240 | 241 | return result; 242 | } 243 | 244 | static ssize_t fs_dev_write_r (struct _reent *r, void *fd, const char *ptr, size_t len) 245 | { 246 | fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; 247 | if(!file->dev) { 248 | r->_errno = ENODEV; 249 | return 0; 250 | } 251 | 252 | if(!file->write) 253 | { 254 | r->_errno = EACCES; 255 | return 0; 256 | } 257 | 258 | OSLockMutex(file->dev->pMutex); 259 | 260 | size_t done = 0; 261 | 262 | while(done < len) 263 | { 264 | size_t write_size = len - done; 265 | 266 | int result = IOSUHAX_FSA_WriteFile(file->dev->fsaFd, ptr + done, 0x01, write_size, file->fd, 0); 267 | if(result < 0) 268 | { 269 | r->_errno = result; 270 | break; 271 | } 272 | else if(result == 0) 273 | { 274 | if(write_size > 0) 275 | done = 0; 276 | break; 277 | } 278 | else 279 | { 280 | done += result; 281 | file->pos += result; 282 | } 283 | } 284 | 285 | OSUnlockMutex(file->dev->pMutex); 286 | return done; 287 | } 288 | 289 | static ssize_t fs_dev_read_r (struct _reent *r, void *fd, char *ptr, size_t len) 290 | { 291 | fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; 292 | if(!file->dev) { 293 | r->_errno = ENODEV; 294 | return 0; 295 | } 296 | 297 | if(!file->read) 298 | { 299 | r->_errno = EACCES; 300 | return 0; 301 | } 302 | 303 | OSLockMutex(file->dev->pMutex); 304 | 305 | size_t done = 0; 306 | 307 | while(done < len) 308 | { 309 | size_t read_size = len - done; 310 | 311 | int result = IOSUHAX_FSA_ReadFile(file->dev->fsaFd, ptr + done, 0x01, read_size, file->fd, 0); 312 | if(result < 0) 313 | { 314 | r->_errno = result; 315 | done = 0; 316 | break; 317 | } 318 | else if(result == 0) 319 | { 320 | //! TODO: error on read_size > 0 321 | break; 322 | } 323 | else 324 | { 325 | done += result; 326 | file->pos += result; 327 | } 328 | } 329 | 330 | OSUnlockMutex(file->dev->pMutex); 331 | return done; 332 | } 333 | 334 | 335 | static int fs_dev_fstat_r (struct _reent *r, void *fd, struct stat *st) 336 | { 337 | fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; 338 | if(!file->dev) { 339 | r->_errno = ENODEV; 340 | return -1; 341 | } 342 | 343 | OSLockMutex(file->dev->pMutex); 344 | 345 | // Zero out the stat buffer 346 | memset(st, 0, sizeof(struct stat)); 347 | 348 | fileStat_s stats; 349 | int result = IOSUHAX_FSA_StatFile(file->dev->fsaFd, (int)fd, &stats); 350 | if(result != 0) { 351 | r->_errno = result; 352 | OSUnlockMutex(file->dev->pMutex); 353 | return -1; 354 | } 355 | 356 | st->st_mode = S_IFREG; 357 | st->st_size = stats.size; 358 | st->st_blocks = (stats.size + 511) >> 9; 359 | st->st_nlink = 1; 360 | 361 | // Fill in the generic entry stats 362 | st->st_dev = stats.id; 363 | st->st_uid = stats.owner_id; 364 | st->st_gid = stats.group_id; 365 | st->st_ino = stats.id; 366 | st->st_atime = stats.mtime; 367 | st->st_ctime = stats.ctime; 368 | st->st_mtime = stats.mtime; 369 | OSUnlockMutex(file->dev->pMutex); 370 | return 0; 371 | } 372 | 373 | static int fs_dev_ftruncate_r (struct _reent *r, void *fd, off_t len) 374 | { 375 | fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; 376 | if(!file->dev) { 377 | r->_errno = ENODEV; 378 | return -1; 379 | } 380 | 381 | r->_errno = ENOTSUP; 382 | // TODO 383 | return -1; 384 | } 385 | 386 | static int fs_dev_fsync_r (struct _reent *r, void *fd) 387 | { 388 | fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; 389 | if(!file->dev) { 390 | r->_errno = ENODEV; 391 | return -1; 392 | } 393 | 394 | r->_errno = ENOTSUP; 395 | // TODO 396 | return -1; 397 | } 398 | 399 | static int fs_dev_stat_r (struct _reent *r, const char *path, struct stat *st) 400 | { 401 | fs_dev_private_t *dev = fs_dev_get_device_data(path); 402 | if(!dev) { 403 | r->_errno = ENODEV; 404 | return -1; 405 | } 406 | 407 | OSLockMutex(dev->pMutex); 408 | 409 | // Zero out the stat buffer 410 | memset(st, 0, sizeof(struct stat)); 411 | 412 | char *real_path = fs_dev_real_path(path, dev); 413 | if(!real_path) { 414 | r->_errno = ENOMEM; 415 | OSUnlockMutex(dev->pMutex); 416 | return -1; 417 | } 418 | 419 | fileStat_s stats; 420 | 421 | int result = IOSUHAX_FSA_GetStat(dev->fsaFd, real_path, &stats); 422 | 423 | free(real_path); 424 | 425 | if(result < 0) { 426 | r->_errno = result; 427 | OSUnlockMutex(dev->pMutex); 428 | return -1; 429 | } 430 | 431 | // mark root also as directory 432 | st->st_mode = ((stats.flag & 0x80000000) || (strlen(dev->mount_path) + 1 == strlen(real_path)))? S_IFDIR : S_IFREG; 433 | st->st_nlink = 1; 434 | st->st_size = stats.size; 435 | st->st_blocks = (stats.size + 511) >> 9; 436 | // Fill in the generic entry stats 437 | st->st_dev = stats.id; 438 | st->st_uid = stats.owner_id; 439 | st->st_gid = stats.group_id; 440 | st->st_ino = stats.id; 441 | st->st_atime = stats.mtime; 442 | st->st_ctime = stats.ctime; 443 | st->st_mtime = stats.mtime; 444 | 445 | OSUnlockMutex(dev->pMutex); 446 | 447 | return 0; 448 | } 449 | 450 | static int fs_dev_link_r (struct _reent *r, const char *existing, const char *newLink) 451 | { 452 | r->_errno = ENOTSUP; 453 | return -1; 454 | } 455 | 456 | static int fs_dev_unlink_r (struct _reent *r, const char *name) 457 | { 458 | fs_dev_private_t *dev = fs_dev_get_device_data(name); 459 | if(!dev) { 460 | r->_errno = ENODEV; 461 | return -1; 462 | } 463 | 464 | OSLockMutex(dev->pMutex); 465 | 466 | char *real_path = fs_dev_real_path(name, dev); 467 | if(!real_path) { 468 | r->_errno = ENOMEM; 469 | OSUnlockMutex(dev->pMutex); 470 | return -1; 471 | } 472 | 473 | int result = IOSUHAX_FSA_Remove(dev->fsaFd, real_path); 474 | 475 | free(real_path); 476 | 477 | OSUnlockMutex(dev->pMutex); 478 | 479 | if(result < 0) { 480 | r->_errno = result; 481 | return -1; 482 | } 483 | 484 | return result; 485 | } 486 | 487 | static int fs_dev_chdir_r (struct _reent *r, const char *name) 488 | { 489 | fs_dev_private_t *dev = fs_dev_get_device_data(name); 490 | if(!dev) { 491 | r->_errno = ENODEV; 492 | return -1; 493 | } 494 | 495 | OSLockMutex(dev->pMutex); 496 | 497 | char *real_path = fs_dev_real_path(name, dev); 498 | if(!real_path) { 499 | r->_errno = ENOMEM; 500 | OSUnlockMutex(dev->pMutex); 501 | return -1; 502 | } 503 | 504 | int result = IOSUHAX_FSA_ChangeDir(dev->fsaFd, real_path); 505 | 506 | free(real_path); 507 | 508 | OSUnlockMutex(dev->pMutex); 509 | 510 | if(result < 0) { 511 | r->_errno = result; 512 | return -1; 513 | } 514 | 515 | return 0; 516 | } 517 | 518 | static int fs_dev_rename_r (struct _reent *r, const char *oldName, const char *newName) 519 | { 520 | fs_dev_private_t *dev = fs_dev_get_device_data(oldName); 521 | if(!dev) { 522 | r->_errno = ENODEV; 523 | return -1; 524 | } 525 | 526 | OSLockMutex(dev->pMutex); 527 | 528 | char *real_oldpath = fs_dev_real_path(oldName, dev); 529 | if(!real_oldpath) { 530 | r->_errno = ENOMEM; 531 | OSUnlockMutex(dev->pMutex); 532 | return -1; 533 | } 534 | char *real_newpath = fs_dev_real_path(newName, dev); 535 | if(!real_newpath) { 536 | r->_errno = ENOMEM; 537 | free(real_oldpath); 538 | OSUnlockMutex(dev->pMutex); 539 | return -1; 540 | } 541 | 542 | //! TODO 543 | int result = -ENOTSUP; 544 | 545 | free(real_oldpath); 546 | free(real_newpath); 547 | 548 | OSUnlockMutex(dev->pMutex); 549 | 550 | if(result < 0) { 551 | r->_errno = result; 552 | return -1; 553 | } 554 | 555 | return 0; 556 | 557 | } 558 | 559 | static int fs_dev_mkdir_r (struct _reent *r, const char *path, int mode) 560 | { 561 | fs_dev_private_t *dev = fs_dev_get_device_data(path); 562 | if(!dev) { 563 | r->_errno = ENODEV; 564 | return -1; 565 | } 566 | 567 | OSLockMutex(dev->pMutex); 568 | 569 | char *real_path = fs_dev_real_path(path, dev); 570 | if(!real_path) { 571 | r->_errno = ENOMEM; 572 | OSUnlockMutex(dev->pMutex); 573 | return -1; 574 | } 575 | 576 | int result = IOSUHAX_FSA_MakeDir(dev->fsaFd, real_path, mode); 577 | 578 | free(real_path); 579 | 580 | OSUnlockMutex(dev->pMutex); 581 | 582 | if(result < 0) { 583 | r->_errno = result; 584 | return -1; 585 | } 586 | 587 | return 0; 588 | } 589 | 590 | static int fs_dev_chmod_r (struct _reent *r, const char *path, int mode) 591 | { 592 | fs_dev_private_t *dev = fs_dev_get_device_data(path); 593 | if(!dev) { 594 | r->_errno = ENODEV; 595 | return -1; 596 | } 597 | 598 | OSLockMutex(dev->pMutex); 599 | 600 | char *real_path = fs_dev_real_path(path, dev); 601 | if(!real_path) { 602 | r->_errno = ENOMEM; 603 | OSUnlockMutex(dev->pMutex); 604 | return -1; 605 | } 606 | 607 | int result = IOSUHAX_FSA_ChangeMode(dev->fsaFd, real_path, mode); 608 | 609 | free(real_path); 610 | 611 | OSUnlockMutex(dev->pMutex); 612 | 613 | if(result < 0) { 614 | r->_errno = result; 615 | return -1; 616 | } 617 | 618 | return 0; 619 | } 620 | 621 | static int fs_dev_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf) 622 | { 623 | fs_dev_private_t *dev = fs_dev_get_device_data(path); 624 | if(!dev) { 625 | r->_errno = ENODEV; 626 | return -1; 627 | } 628 | 629 | OSLockMutex(dev->pMutex); 630 | 631 | // Zero out the stat buffer 632 | memset(buf, 0, sizeof(struct statvfs)); 633 | 634 | char *real_path = fs_dev_real_path(path, dev); 635 | if(!real_path) { 636 | r->_errno = ENOMEM; 637 | OSUnlockMutex(dev->pMutex); 638 | return -1; 639 | } 640 | 641 | uint64_t size; 642 | 643 | int result = IOSUHAX_FSA_GetDeviceInfo(dev->fsaFd, real_path, 0x00, (uint32_t*)&size); 644 | 645 | free(real_path); 646 | 647 | if(result < 0) { 648 | r->_errno = result; 649 | OSUnlockMutex(dev->pMutex); 650 | return -1; 651 | } 652 | 653 | // File system block size 654 | buf->f_bsize = 512; 655 | 656 | // Fundamental file system block size 657 | buf->f_frsize = 512; 658 | 659 | // Total number of blocks on file system in units of f_frsize 660 | buf->f_blocks = size >> 9; // this is unknown 661 | 662 | // Free blocks available for all and for non-privileged processes 663 | buf->f_bfree = buf->f_bavail = size >> 9; 664 | 665 | // Number of inodes at this point in time 666 | buf->f_files = 0xffffffff; 667 | 668 | // Free inodes available for all and for non-privileged processes 669 | buf->f_ffree = 0xffffffff; 670 | 671 | // File system id 672 | buf->f_fsid = (int)dev; 673 | 674 | // Bit mask of f_flag values. 675 | buf->f_flag = 0; 676 | 677 | // Maximum length of filenames 678 | buf->f_namemax = 255; 679 | 680 | OSUnlockMutex(dev->pMutex); 681 | 682 | return 0; 683 | } 684 | 685 | static DIR_ITER *fs_dev_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path) 686 | { 687 | fs_dev_private_t *dev = fs_dev_get_device_data(path); 688 | if(!dev) { 689 | r->_errno = ENODEV; 690 | return NULL; 691 | } 692 | 693 | fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct; 694 | 695 | OSLockMutex(dev->pMutex); 696 | 697 | char *real_path = fs_dev_real_path(path, dev); 698 | if(!real_path) { 699 | r->_errno = ENOMEM; 700 | OSUnlockMutex(dev->pMutex); 701 | return NULL; 702 | } 703 | 704 | int dirHandle; 705 | 706 | int result = IOSUHAX_FSA_OpenDir(dev->fsaFd, real_path, &dirHandle); 707 | 708 | free(real_path); 709 | 710 | OSUnlockMutex(dev->pMutex); 711 | 712 | if(result < 0) 713 | { 714 | r->_errno = result; 715 | return NULL; 716 | } 717 | 718 | dirIter->dev = dev; 719 | dirIter->dirHandle = dirHandle; 720 | 721 | return dirState; 722 | } 723 | 724 | static int fs_dev_dirclose_r (struct _reent *r, DIR_ITER *dirState) 725 | { 726 | fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct; 727 | if(!dirIter->dev) { 728 | r->_errno = ENODEV; 729 | return -1; 730 | } 731 | 732 | OSLockMutex(dirIter->dev->pMutex); 733 | 734 | int result = IOSUHAX_FSA_CloseDir(dirIter->dev->fsaFd, dirIter->dirHandle); 735 | 736 | OSUnlockMutex(dirIter->dev->pMutex); 737 | 738 | if(result < 0) 739 | { 740 | r->_errno = result; 741 | return -1; 742 | } 743 | return 0; 744 | } 745 | 746 | static int fs_dev_dirreset_r (struct _reent *r, DIR_ITER *dirState) 747 | { 748 | fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct; 749 | if(!dirIter->dev) { 750 | r->_errno = ENODEV; 751 | return -1; 752 | } 753 | 754 | OSLockMutex(dirIter->dev->pMutex); 755 | 756 | int result = IOSUHAX_FSA_RewindDir(dirIter->dev->fsaFd, dirIter->dirHandle); 757 | 758 | OSUnlockMutex(dirIter->dev->pMutex); 759 | 760 | if(result < 0) 761 | { 762 | r->_errno = result; 763 | return -1; 764 | } 765 | return 0; 766 | } 767 | 768 | static int fs_dev_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st) 769 | { 770 | fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct; 771 | if(!dirIter->dev) { 772 | r->_errno = ENODEV; 773 | return -1; 774 | } 775 | 776 | OSLockMutex(dirIter->dev->pMutex); 777 | 778 | directoryEntry_s * dir_entry = malloc(sizeof(directoryEntry_s)); 779 | 780 | int result = IOSUHAX_FSA_ReadDir(dirIter->dev->fsaFd, dirIter->dirHandle, dir_entry); 781 | if(result < 0) 782 | { 783 | free(dir_entry); 784 | r->_errno = result; 785 | OSUnlockMutex(dirIter->dev->pMutex); 786 | return -1; 787 | } 788 | 789 | // Fetch the current entry 790 | strcpy(filename, dir_entry->name); 791 | 792 | if(st) 793 | { 794 | memset(st, 0, sizeof(struct stat)); 795 | st->st_mode = (dir_entry->stat.flag & 0x80000000) ? S_IFDIR : S_IFREG; 796 | st->st_nlink = 1; 797 | st->st_size = dir_entry->stat.size; 798 | st->st_blocks = (dir_entry->stat.size + 511) >> 9; 799 | st->st_dev = dir_entry->stat.id; 800 | st->st_uid = dir_entry->stat.owner_id; 801 | st->st_gid = dir_entry->stat.group_id; 802 | st->st_ino = dir_entry->stat.id; 803 | st->st_atime = dir_entry->stat.mtime; 804 | st->st_ctime = dir_entry->stat.ctime; 805 | st->st_mtime = dir_entry->stat.mtime; 806 | } 807 | 808 | free(dir_entry); 809 | OSUnlockMutex(dirIter->dev->pMutex); 810 | return 0; 811 | } 812 | 813 | // NTFS device driver devoptab 814 | static const devoptab_t devops_fs = { 815 | NULL, /* Device name */ 816 | sizeof (fs_dev_file_state_t), 817 | fs_dev_open_r, 818 | fs_dev_close_r, 819 | fs_dev_write_r, 820 | fs_dev_read_r, 821 | fs_dev_seek_r, 822 | fs_dev_fstat_r, 823 | fs_dev_stat_r, 824 | fs_dev_link_r, 825 | fs_dev_unlink_r, 826 | fs_dev_chdir_r, 827 | fs_dev_rename_r, 828 | fs_dev_mkdir_r, 829 | sizeof (fs_dev_dir_entry_t), 830 | fs_dev_diropen_r, 831 | fs_dev_dirreset_r, 832 | fs_dev_dirnext_r, 833 | fs_dev_dirclose_r, 834 | fs_dev_statvfs_r, 835 | fs_dev_ftruncate_r, 836 | fs_dev_fsync_r, 837 | fs_dev_chmod_r, 838 | NULL, /* fs_dev_fchmod_r */ 839 | NULL /* Device data */ 840 | }; 841 | 842 | static int fs_dev_add_device (const char *name, const char *mount_path, int fsaFd, int isMounted) 843 | { 844 | devoptab_t *dev = NULL; 845 | char *devname = NULL; 846 | char *devpath = NULL; 847 | int i; 848 | 849 | // Sanity check 850 | if (!name) { 851 | errno = EINVAL; 852 | return -1; 853 | } 854 | 855 | // Allocate a devoptab for this device 856 | dev = (devoptab_t *) malloc(sizeof(devoptab_t) + strlen(name) + 1); 857 | if (!dev) { 858 | errno = ENOMEM; 859 | return -1; 860 | } 861 | 862 | // Use the space allocated at the end of the devoptab for storing the device name 863 | devname = (char*)(dev + 1); 864 | strcpy(devname, name); 865 | 866 | // create private data 867 | fs_dev_private_t *priv = (fs_dev_private_t *)malloc(sizeof(fs_dev_private_t) + strlen(mount_path) + 1); 868 | if(!priv) { 869 | free(dev); 870 | errno = ENOMEM; 871 | return -1; 872 | } 873 | 874 | devpath = (char*)(priv+1); 875 | strcpy(devpath, mount_path); 876 | 877 | // setup private data 878 | priv->mount_path = devpath; 879 | priv->fsaFd = fsaFd; 880 | priv->mounted = isMounted; 881 | priv->pMutex = malloc(OS_MUTEX_SIZE); 882 | 883 | if(!priv->pMutex) { 884 | free(dev); 885 | free(priv); 886 | errno = ENOMEM; 887 | return -1; 888 | } 889 | 890 | OSInitMutex(priv->pMutex); 891 | 892 | // Setup the devoptab 893 | memcpy(dev, &devops_fs, sizeof(devoptab_t)); 894 | dev->name = devname; 895 | dev->deviceData = priv; 896 | 897 | // Add the device to the devoptab table (if there is a free slot) 898 | for (i = 3; i < STD_MAX; i++) { 899 | if (devoptab_list[i] == devoptab_list[0]) { 900 | devoptab_list[i] = dev; 901 | return 0; 902 | } 903 | } 904 | 905 | // failure, free all memory 906 | free(priv); 907 | free(dev); 908 | 909 | // If we reach here then there are no free slots in the devoptab table for this device 910 | errno = EADDRNOTAVAIL; 911 | return -1; 912 | } 913 | 914 | static int fs_dev_remove_device (const char *path) 915 | { 916 | const devoptab_t *devoptab = NULL; 917 | char name[128] = {0}; 918 | int i; 919 | 920 | // Get the device name from the path 921 | strncpy(name, path, 127); 922 | strtok(name, ":/"); 923 | 924 | // Find and remove the specified device from the devoptab table 925 | // NOTE: We do this manually due to a 'bug' in RemoveDevice 926 | // which ignores names with suffixes and causes names 927 | // like "ntfs" and "ntfs1" to be seen as equals 928 | for (i = 3; i < STD_MAX; i++) { 929 | devoptab = devoptab_list[i]; 930 | if (devoptab && devoptab->name) { 931 | if (strcmp(name, devoptab->name) == 0) { 932 | devoptab_list[i] = devoptab_list[0]; 933 | 934 | if(devoptab->deviceData) 935 | { 936 | fs_dev_private_t *priv = (fs_dev_private_t *)devoptab->deviceData; 937 | 938 | if(priv->mounted) 939 | IOSUHAX_FSA_Unmount(priv->fsaFd, priv->mount_path, 2); 940 | 941 | if(priv->pMutex) 942 | free(priv->pMutex); 943 | free(devoptab->deviceData); 944 | } 945 | 946 | free((devoptab_t*)devoptab); 947 | return 0; 948 | } 949 | } 950 | } 951 | 952 | return -1; 953 | } 954 | 955 | int mount_fs(const char *virt_name, int fsaFd, const char *dev_path, const char *mount_path) 956 | { 957 | int isMounted = 0; 958 | 959 | if(dev_path) 960 | { 961 | isMounted = 1; 962 | 963 | int res = IOSUHAX_FSA_Mount(fsaFd, dev_path, mount_path, 2, 0, 0); 964 | if(res != 0) 965 | { 966 | return res; 967 | } 968 | } 969 | 970 | return fs_dev_add_device(virt_name, mount_path, fsaFd, isMounted); 971 | } 972 | 973 | int unmount_fs(const char *virt_name) 974 | { 975 | return fs_dev_remove_device(virt_name); 976 | } 977 | -------------------------------------------------------------------------------- /source/iosuhax_devoptab.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2015 3 | * by Dimok 4 | * 5 | * This software is provided 'as-is', without any express or implied 6 | * warranty. In no event will the authors be held liable for any 7 | * damages arising from the use of this software. 8 | * 9 | * Permission is granted to anyone to use this software for any 10 | * purpose, including commercial applications, and to alter it and 11 | * redistribute it freely, subject to the following restrictions: 12 | * 13 | * 1. The origin of this software must not be misrepresented; you 14 | * must not claim that you wrote the original software. If you use 15 | * this software in a product, an acknowledgment in the product 16 | * documentation would be appreciated but is not required. 17 | * 18 | * 2. Altered source versions must be plainly marked as such, and 19 | * must not be misrepresented as being the original software. 20 | * 21 | * 3. This notice may not be removed or altered from any source 22 | * distribution. 23 | ***************************************************************************/ 24 | #ifndef __IOSUHAX_DEVOPTAB_H_ 25 | #define __IOSUHAX_DEVOPTAB_H_ 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | //! virtual name example: sd or odd (for sd:/ or odd:/ access) 32 | //! fsaFd: fd received by IOSUHAX_FSA_Open(); 33 | //! dev_path: (optional) if a device should be mounted to the mount_path. If NULL no IOSUHAX_FSA_Mount is not executed. 34 | //! mount_path: path to map to virtual device name 35 | int mount_fs(const char *virt_name, int fsaFd, const char *dev_path, const char *mount_path); 36 | int unmount_fs(const char *virt_name); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | 42 | #endif // __IOSUHAX_DEVOPTAB_H_ 43 | -------------------------------------------------------------------------------- /source/iosuhax_disc_interface.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2016 3 | * by Dimok 4 | * 5 | * This software is provided 'as-is', without any express or implied 6 | * warranty. In no event will the authors be held liable for any 7 | * damages arising from the use of this software. 8 | * 9 | * Permission is granted to anyone to use this software for any 10 | * purpose, including commercial applications, and to alter it and 11 | * redistribute it freely, subject to the following restrictions: 12 | * 13 | * 1. The origin of this software must not be misrepresented; you 14 | * must not claim that you wrote the original software. If you use 15 | * this software in a product, an acknowledgment in the product 16 | * documentation would be appreciated but is not required. 17 | * 18 | * 2. Altered source versions must be plainly marked as such, and 19 | * must not be misrepresented as being the original software. 20 | * 21 | * 3. This notice may not be removed or altered from any source 22 | * distribution. 23 | ***************************************************************************/ 24 | #include 25 | #include 26 | #include "iosuhax.h" 27 | #include "iosuhax_disc_interface.h" 28 | 29 | #define FSA_REF_SD 0x01 30 | #define FSA_REF_USB 0x02 31 | 32 | static int initialized = 0; 33 | 34 | static int fsaFdSd = 0; 35 | static int fsaFdUsb = 0; 36 | static int sdioFd = 0; 37 | static int usbFd = 0; 38 | 39 | static void IOSUHAX_disc_io_initialize(void) 40 | { 41 | if(initialized == 0) 42 | { 43 | initialized = 1; 44 | fsaFdSd = -1; 45 | fsaFdUsb = -1; 46 | sdioFd = -1; 47 | usbFd = -1; 48 | } 49 | } 50 | 51 | static bool IOSUHAX_disc_io_fsa_open(int fsaFd) 52 | { 53 | IOSUHAX_disc_io_initialize(); 54 | 55 | if(IOSUHAX_Open(NULL) < 0) 56 | return false; 57 | 58 | if(fsaFd == FSA_REF_SD) 59 | { 60 | if(fsaFdSd < 0) 61 | { 62 | fsaFdSd = IOSUHAX_FSA_Open(); 63 | } 64 | 65 | if(fsaFdSd >= 0) 66 | return true; 67 | } 68 | else if(fsaFd == FSA_REF_USB) 69 | { 70 | if(fsaFdUsb < 0) 71 | { 72 | fsaFdUsb = IOSUHAX_FSA_Open(); 73 | } 74 | 75 | if(fsaFdUsb >= 0) 76 | return true; 77 | } 78 | 79 | return false; 80 | } 81 | 82 | static void IOSUHAX_disc_io_fsa_close(int fsaFd) 83 | { 84 | if(fsaFd == FSA_REF_SD) 85 | { 86 | if(fsaFdSd >= 0) 87 | { 88 | IOSUHAX_FSA_Close(fsaFdSd); 89 | fsaFdSd = -1; 90 | } 91 | } 92 | else if(fsaFd == FSA_REF_USB) 93 | { 94 | if(fsaFdUsb >= 0) 95 | { 96 | IOSUHAX_FSA_Close(fsaFdUsb); 97 | fsaFdUsb = -1; 98 | } 99 | } 100 | } 101 | 102 | static bool IOSUHAX_sdio_startup(void) 103 | { 104 | if(!IOSUHAX_disc_io_fsa_open(FSA_REF_SD)) 105 | return false; 106 | 107 | if(sdioFd < 0) 108 | { 109 | int res = IOSUHAX_FSA_RawOpen(fsaFdSd, "/dev/sdcard01", &sdioFd); 110 | if(res < 0) 111 | { 112 | IOSUHAX_disc_io_fsa_close(FSA_REF_SD); 113 | sdioFd = -1; 114 | } 115 | } 116 | 117 | return (sdioFd >= 0); 118 | } 119 | 120 | static bool IOSUHAX_sdio_isInserted(void) 121 | { 122 | //! TODO: check for SD card inserted with IOSUHAX_FSA_GetDeviceInfo() 123 | return initialized && (fsaFdSd >= 0) && (sdioFd >= 0); 124 | } 125 | 126 | static bool IOSUHAX_sdio_clearStatus(void) 127 | { 128 | return true; 129 | } 130 | 131 | static bool IOSUHAX_sdio_shutdown(void) 132 | { 133 | if(!IOSUHAX_sdio_isInserted()) 134 | return false; 135 | 136 | IOSUHAX_FSA_RawClose(fsaFdSd, sdioFd); 137 | IOSUHAX_disc_io_fsa_close(FSA_REF_SD); 138 | sdioFd = -1; 139 | return true; 140 | } 141 | 142 | static bool IOSUHAX_sdio_readSectors(uint32_t sector, uint32_t numSectors, void* buffer) 143 | { 144 | if(!IOSUHAX_sdio_isInserted()) 145 | return false; 146 | 147 | int res = IOSUHAX_FSA_RawRead(fsaFdSd, buffer, 512, numSectors, sector, sdioFd); 148 | if(res < 0) 149 | { 150 | return false; 151 | } 152 | 153 | return true; 154 | } 155 | 156 | static bool IOSUHAX_sdio_writeSectors(uint32_t sector, uint32_t numSectors, const void* buffer) 157 | { 158 | if(!IOSUHAX_sdio_isInserted()) 159 | return false; 160 | 161 | int res = IOSUHAX_FSA_RawWrite(fsaFdSd, buffer, 512, numSectors, sector, sdioFd); 162 | if(res < 0) 163 | { 164 | return false; 165 | } 166 | 167 | return true; 168 | } 169 | 170 | const DISC_INTERFACE IOSUHAX_sdio_disc_interface = 171 | { 172 | DEVICE_TYPE_WII_U_SD, 173 | FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_U_SD, 174 | IOSUHAX_sdio_startup, 175 | IOSUHAX_sdio_isInserted, 176 | IOSUHAX_sdio_readSectors, 177 | IOSUHAX_sdio_writeSectors, 178 | IOSUHAX_sdio_clearStatus, 179 | IOSUHAX_sdio_shutdown 180 | }; 181 | 182 | static bool IOSUHAX_usb_startup(void) 183 | { 184 | if(!IOSUHAX_disc_io_fsa_open(FSA_REF_USB)) 185 | return false; 186 | 187 | if(usbFd < 0) 188 | { 189 | int res = IOSUHAX_FSA_RawOpen(fsaFdUsb, "/dev/usb01", &usbFd); 190 | if(res < 0) 191 | { 192 | res = IOSUHAX_FSA_RawOpen(fsaFdUsb, "/dev/usb02", &usbFd); 193 | if(res < 0) 194 | { 195 | IOSUHAX_disc_io_fsa_close(FSA_REF_USB); 196 | usbFd = -1; 197 | } 198 | } 199 | } 200 | return (usbFd >= 0); 201 | } 202 | 203 | static bool IOSUHAX_usb_isInserted(void) 204 | { 205 | return initialized && (fsaFdUsb >= 0) && (usbFd >= 0); 206 | } 207 | 208 | static bool IOSUHAX_usb_clearStatus(void) 209 | { 210 | return true; 211 | } 212 | 213 | static bool IOSUHAX_usb_shutdown(void) 214 | { 215 | if(!IOSUHAX_usb_isInserted()) 216 | return false; 217 | 218 | IOSUHAX_FSA_RawClose(fsaFdUsb, usbFd); 219 | IOSUHAX_disc_io_fsa_close(FSA_REF_USB); 220 | usbFd = -1; 221 | return true; 222 | } 223 | 224 | static bool IOSUHAX_usb_readSectors(uint32_t sector, uint32_t numSectors, void* buffer) 225 | { 226 | if(!IOSUHAX_usb_isInserted()) 227 | return false; 228 | 229 | int res = IOSUHAX_FSA_RawRead(fsaFdUsb, buffer, 512, numSectors, sector, usbFd); 230 | if(res < 0) 231 | { 232 | return false; 233 | } 234 | 235 | return true; 236 | } 237 | 238 | static bool IOSUHAX_usb_writeSectors(uint32_t sector, uint32_t numSectors, const void* buffer) 239 | { 240 | if(!IOSUHAX_usb_isInserted()) 241 | return false; 242 | 243 | int res = IOSUHAX_FSA_RawWrite(fsaFdUsb, buffer, 512, numSectors, sector, usbFd); 244 | if(res < 0) 245 | { 246 | return false; 247 | } 248 | 249 | return true; 250 | } 251 | 252 | const DISC_INTERFACE IOSUHAX_usb_disc_interface = 253 | { 254 | DEVICE_TYPE_WII_U_USB, 255 | FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_U_USB, 256 | IOSUHAX_usb_startup, 257 | IOSUHAX_usb_isInserted, 258 | IOSUHAX_usb_readSectors, 259 | IOSUHAX_usb_writeSectors, 260 | IOSUHAX_usb_clearStatus, 261 | IOSUHAX_usb_shutdown 262 | }; 263 | -------------------------------------------------------------------------------- /source/iosuhax_disc_interface.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2016 3 | * by Dimok 4 | * 5 | * This software is provided 'as-is', without any express or implied 6 | * warranty. In no event will the authors be held liable for any 7 | * damages arising from the use of this software. 8 | * 9 | * Permission is granted to anyone to use this software for any 10 | * purpose, including commercial applications, and to alter it and 11 | * redistribute it freely, subject to the following restrictions: 12 | * 13 | * 1. The origin of this software must not be misrepresented; you 14 | * must not claim that you wrote the original software. If you use 15 | * this software in a product, an acknowledgment in the product 16 | * documentation would be appreciated but is not required. 17 | * 18 | * 2. Altered source versions must be plainly marked as such, and 19 | * must not be misrepresented as being the original software. 20 | * 21 | * 3. This notice may not be removed or altered from any source 22 | * distribution. 23 | ***************************************************************************/ 24 | #ifndef _IOSUHAX_DISC_INTERFACE_H_ 25 | #define _IOSUHAX_DISC_INTERFACE_H_ 26 | 27 | #include 28 | #include 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | #define DEVICE_TYPE_WII_U_SD (('W'<<24)|('U'<<16)|('S'<<8)|'D') 35 | #define DEVICE_TYPE_WII_U_USB (('W'<<24)|('U'<<16)|('S'<<8)|'B') 36 | #define FEATURE_WII_U_SD 0x00001000 37 | #define FEATURE_WII_U_USB 0x00002000 38 | 39 | #ifndef OGC_DISC_IO_INCLUDE 40 | typedef uint32_t sec_t; 41 | 42 | #define FEATURE_MEDIUM_CANREAD 0x00000001 43 | #define FEATURE_MEDIUM_CANWRITE 0x00000002 44 | 45 | typedef bool (* FN_MEDIUM_STARTUP)(void) ; 46 | typedef bool (* FN_MEDIUM_ISINSERTED)(void) ; 47 | typedef bool (* FN_MEDIUM_READSECTORS)(uint32_t sector, uint32_t numSectors, void* buffer) ; 48 | typedef bool (* FN_MEDIUM_WRITESECTORS)(uint32_t sector, uint32_t numSectors, const void* buffer) ; 49 | typedef bool (* FN_MEDIUM_CLEARSTATUS)(void) ; 50 | typedef bool (* FN_MEDIUM_SHUTDOWN)(void) ; 51 | 52 | struct DISC_INTERFACE_STRUCT { 53 | unsigned long ioType ; 54 | unsigned long features ; 55 | FN_MEDIUM_STARTUP startup ; 56 | FN_MEDIUM_ISINSERTED isInserted ; 57 | FN_MEDIUM_READSECTORS readSectors ; 58 | FN_MEDIUM_WRITESECTORS writeSectors ; 59 | FN_MEDIUM_CLEARSTATUS clearStatus ; 60 | FN_MEDIUM_SHUTDOWN shutdown ; 61 | } ; 62 | 63 | typedef struct DISC_INTERFACE_STRUCT DISC_INTERFACE ; 64 | #endif 65 | 66 | extern const DISC_INTERFACE IOSUHAX_sdio_disc_interface; 67 | extern const DISC_INTERFACE IOSUHAX_usb_disc_interface; 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /source/os_functions.h: -------------------------------------------------------------------------------- 1 | #ifndef __OS_FUNCTIONS_H_ 2 | #define __OS_FUNCTIONS_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #define OS_MUTEX_SIZE 44 9 | 10 | #ifndef __WUT__ 11 | //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 12 | //! Mutex functions 13 | //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 14 | extern void (* OSInitMutex)(void* mutex); 15 | extern void (* OSLockMutex)(void* mutex); 16 | extern void (* OSUnlockMutex)(void* mutex); 17 | 18 | //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 19 | //! IOS function 20 | //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 21 | 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); 22 | extern int (*IOS_Open)(char *path, unsigned int mode); 23 | extern int (*IOS_Close)(int fd); 24 | #else 25 | //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 26 | //! Mutex functions 27 | //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 28 | extern void OSInitMutex(void* mutex); 29 | extern void OSLockMutex(void* mutex); 30 | extern void OSUnlockMutex(void* mutex); 31 | 32 | //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 33 | //! IOS function 34 | //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 35 | 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); 36 | extern int IOS_Open(char *path, unsigned int mode); 37 | extern int IOS_Close(int fd); 38 | #endif // __WUT__ 39 | 40 | #ifdef __cplusplus 41 | } 42 | #endif 43 | 44 | #endif // __OS_FUNCTIONS_H_ 45 | --------------------------------------------------------------------------------