├── NETFS.ELF ├── hdl_info ├── main.h ├── exports.tab ├── Makefile ├── hdl.h ├── imports.lst ├── irx_imports.h ├── apa.h ├── hdd.h ├── main.c ├── ps2_hdd.h ├── hdl.c ├── hdd.c └── apa.c ├── .clang-format-ignore ├── timer.c ├── AllowDVDV ├── imports.lst ├── irx_imports.h ├── Makefile └── AllowDVDV.c ├── docs ├── TODO.txt ├── NFS.CNF ├── SMB2.CNF ├── keyboard.txt ├── FileBrowser sort+display modes.txt ├── New resolutions.txt └── Multiple USB_mass drives and partitions.txt ├── vmc_fs ├── Makefile ├── imports.lst ├── irx_imports.h ├── vmc_fs.c ├── vmc_fat.c ├── vmc_ps2.c └── vmc.h ├── .gitattributes ├── loader ├── Makefile ├── linkfile ├── Rules.make └── loader.c ├── .editorconfig ├── .gitignore ├── hdl_rpc.h ├── .github └── workflows │ ├── check-format.yml │ └── compilation.yml ├── nfs.h ├── smb2.h ├── hdl_rpc.c ├── README.md ├── chkesr.c ├── Rules.make ├── .clang-format ├── Makefile ├── elf.c ├── pad.c ├── launchelf.h ├── nfs.c ├── smb2.c ├── makeicon.c └── lang.c /NETFS.ELF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahlberg/wLaunchELF/HEAD/NETFS.ELF -------------------------------------------------------------------------------- /hdl_info/main.h: -------------------------------------------------------------------------------- 1 | //Memory allocation helpers 2 | void *malloc(int size); 3 | void free(void *ptr); 4 | -------------------------------------------------------------------------------- /.clang-format-ignore: -------------------------------------------------------------------------------- 1 | # ignore files with non-unicode symbols 2 | ./jpgviewer.c 3 | ./draw.c 4 | ./makeicon.c 5 | -------------------------------------------------------------------------------- /timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "launchelf.h" 3 | 4 | // Timer Count 5 | u64 Timer(void) 6 | { 7 | return (clock() / (CLOCKS_PER_SEC / 1000)); 8 | } 9 | -------------------------------------------------------------------------------- /AllowDVDV/imports.lst: -------------------------------------------------------------------------------- 1 | sysclib_IMPORTS_start 2 | I_memset 3 | I_memcpy 4 | sysclib_IMPORTS_end 5 | 6 | ioman_IMPORTS_start 7 | I_open 8 | I_close 9 | ioman_IMPORTS_end 10 | -------------------------------------------------------------------------------- /AllowDVDV/irx_imports.h: -------------------------------------------------------------------------------- 1 | #ifndef IOP_IRX_IMPORTS_H 2 | #define IOP_IRX_IMPORTS_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /docs/TODO.txt: -------------------------------------------------------------------------------- 1 | -bind button combination for interrupting HDD_manager (cause with 200 partitions it takes 7 minutes and it will be useful to stop hdd manager at some point) 2 | -rewrite FTP part to be more stable 3 | -make SMB (samba share) working 4 | -cleanup code. 5 | -------------------------------------------------------------------------------- /hdl_info/exports.tab: -------------------------------------------------------------------------------- 1 | DECLARE_EXPORT_TABLE(hdl_srv, 1, 1) 2 | DECLARE_EXPORT(_start) 3 | DECLARE_EXPORT(_retonly) 4 | DECLARE_EXPORT(shutdown) 5 | DECLARE_EXPORT(_retonly) 6 | 7 | DECLARE_EXPORT(HdlRenameGame) 8 | 9 | END_EXPORT_TABLE 10 | 11 | void _retonly() {} 12 | -------------------------------------------------------------------------------- /vmc_fs/Makefile: -------------------------------------------------------------------------------- 1 | IOP_BIN = vmc_fs.irx 2 | IOP_OBJS = vmc_fs.o vmc_io.o vmc_misc.o vmc_fat.o vmc_ps2.o imports.o 3 | 4 | IOP_CFLAGS += -Wall -fno-builtin 5 | IOP_LDFLAGS += -s 6 | 7 | all: $(IOP_BIN) 8 | 9 | clean: 10 | rm -f -r $(IOP_OBJS_DIR) $(IOP_BIN) 11 | 12 | include $(PS2SDK)/Defs.make 13 | include ../Rules.make 14 | -------------------------------------------------------------------------------- /AllowDVDV/Makefile: -------------------------------------------------------------------------------- 1 | IOP_BIN = AllowDVDV.irx 2 | IOP_OBJS = AllowDVDV.o imports.o 3 | 4 | IOP_CFLAGS += -Wall -fno-builtin -D_IOP 5 | IOP_LDFLAGS += -s 6 | IOP_INCS += -I$(PS2SDK)/iop/include -I$(PS2SDK)/common/include 7 | 8 | all: $(IOP_BIN) 9 | 10 | clean: 11 | rm -r -f $(IOP_OBJS_DIR) $(IOP_BIN) 12 | 13 | include $(PS2SDK)/Defs.make 14 | include ../Rules.make 15 | -------------------------------------------------------------------------------- /hdl_info/Makefile: -------------------------------------------------------------------------------- 1 | IOP_BIN = hdl_info.irx 2 | IOP_OBJS = main.o hdd.o apa.o hdl.o imports.o exports.o 3 | 4 | all: $(IOP_BIN) 5 | 6 | run: all 7 | ps2client -h 192.168.0.10 -t 1 execiop host:$(IOP_BIN) 8 | reset: clean 9 | ps2client -h 192.168.0.10 reset 10 | 11 | clean: 12 | rm -f -r $(IOP_OBJS_DIR) $(IOP_BIN) 13 | 14 | include $(PS2SDK)/Defs.make 15 | include $(PS2SDK)/samples/Makefile.pref 16 | include $(PS2SDK)/samples/Makefile.iopglobal 17 | 18 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /loader/Makefile: -------------------------------------------------------------------------------- 1 | 2 | EE_CFLAGS = -D_EE -Os -G0 -Wall 3 | EE_CFLAGS += -fdata-sections -ffunction-sections 4 | EE_LDFLAGS = -Tlinkfile -Wl,-zmax-page-size=128 5 | EE_LDFLAGS += -s -Wl,--gc-sections 6 | 7 | EE_BIN = loader.elf 8 | 9 | EE_OBJS = loader.o 10 | 11 | EE_LIBS = 12 | ifeq ($(DEBUG),1) 13 | EE_LIBS += -ldebug 14 | endif 15 | 16 | all: $(EE_BIN) 17 | 18 | clean: 19 | rm -f -r $(EE_OBJS_DIR) $(EE_BIN) 20 | 21 | include $(PS2SDK)/Defs.make 22 | include Rules.make 23 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig: http://EditorConfig.org 2 | 3 | # Top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | charset = utf-8 12 | 13 | # 4 space indentation 14 | [*.{c,h,js,css,html}] 15 | indent_style = space 16 | indent_size = 4 17 | 18 | # 2 space indentation 19 | [*.{json,xml,yaml,yml}] 20 | indent_style = space 21 | indent_size = 2 22 | 23 | # Tab indentation 24 | [Makefile*, .make, linkfile] 25 | indent_style = tab 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE! Please use 'git ls-files -i --exclude-standard -c' 3 | # command after changing this file, to see if there are 4 | # any tracked files which get ignored after the change. 5 | # 6 | # Normal rules 7 | # 8 | .* 9 | *.a 10 | *.diff 11 | *.elf 12 | *.ELF 13 | *.erl 14 | *.exe 15 | *.irx 16 | *.map 17 | *.o 18 | *.patch 19 | *.rej 20 | *.s 21 | *.zip 22 | *.ZIP 23 | *.a 24 | 25 | # 26 | # files that we don't want to ignore 27 | # 28 | !.gitignore 29 | !.gitattributes 30 | !.github 31 | !.editorconfig 32 | !.clang-format* 33 | 34 | # 35 | # Generated source files 36 | # 37 | githash.h 38 | -------------------------------------------------------------------------------- /hdl_rpc.h: -------------------------------------------------------------------------------- 1 | #ifndef _HDL_RPC_H 2 | #define _HDL_RPC_H 3 | 4 | #define HDL_IRX 0xD0D0D0D 5 | 6 | #define HDL_GETINFO 0x004 7 | #define HDL_RENAME 0x005 8 | 9 | typedef struct 10 | { 11 | char Partition_Name[32 + 1]; 12 | char Name[64 + 1]; 13 | char Startup[8 + 1 + 3 + 1]; 14 | int Is_Dvd; 15 | } GameInfo; 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif /* __cplusplus */ 20 | 21 | int Hdl_Info_BindRpc(void); 22 | int HdlGetGameInfo(char *PartName, GameInfo *Game); 23 | int HdlRenameGame(char *OldName, char *NewName); 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif /* __cplusplus */ 28 | 29 | #endif /* _HDL_RPC_H */ 30 | -------------------------------------------------------------------------------- /vmc_fs/imports.lst: -------------------------------------------------------------------------------- 1 | cdvdman_IMPORTS_start 2 | I_sceCdReadClock 3 | cdvdman_IMPORTS_end 4 | 5 | sysclib_IMPORTS_start 6 | I_strlen 7 | I_strcpy 8 | I_memset 9 | I_strrchr 10 | I_sprintf 11 | I_memcpy 12 | I_memcmp 13 | sysclib_IMPORTS_end 14 | 15 | stdio_IMPORTS_start 16 | I_printf 17 | stdio_IMPORTS_end 18 | 19 | intrman_IMPORTS_start 20 | I_CpuSuspendIntr 21 | I_CpuResumeIntr 22 | intrman_IMPORTS_end 23 | 24 | iomanX_IMPORTS_start 25 | I_open 26 | I_close 27 | I_read 28 | I_write 29 | I_lseek 30 | I_AddDrv 31 | I_DelDrv 32 | iomanX_IMPORTS_end 33 | 34 | sysmem_IMPORTS_start 35 | I_AllocSysMemory 36 | I_FreeSysMemory 37 | sysmem_IMPORTS_end 38 | -------------------------------------------------------------------------------- /.github/workflows/check-format.yml: -------------------------------------------------------------------------------- 1 | name: CI-format-check 2 | 3 | on: 4 | push: 5 | paths: 6 | - "**.h" 7 | - "**.c" 8 | - ".github/workflows/check-format.yml" 9 | - ".clang-format" 10 | pull_request: 11 | paths: 12 | - "**.h" 13 | - "**.c" 14 | - ".github/workflows/check-format.yml" 15 | - ".clang-format" 16 | 17 | jobs: 18 | check-format: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - uses: DoozyX/clang-format-lint-action@v0.12 24 | with: 25 | source: "." 26 | clangFormatVersion: 12 27 | inplace: false 28 | -------------------------------------------------------------------------------- /docs/NFS.CNF: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------- 2 | # File name: NFS.CNF Revision Date: 2021.09.13 3 | # Created by: Ronnie Sahlberg Creation Date: 2021.09.13 4 | # --------------------------------------------------------------------------- 5 | # Purpose: Define NFS servers for the NFS implementation of wLaunchELF 6 | # Optional URL arguments, to for example enable NFSv4, 7 | # can be found in the libnfs README file. 8 | # --------------------------------------------------------------------------- 9 | NAME = BIG-NFS 10 | URL = nfs://10.10.10.10/data/BIG 11 | #---------------------------------------------------------------------------- 12 | # End of file: NFS.CNF 13 | #---------------------------------------------------------------------------- 14 | -------------------------------------------------------------------------------- /hdl_info/hdl.h: -------------------------------------------------------------------------------- 1 | #ifndef _CDVDHDL_H_ 2 | #define _CDVDHDL_H_ 3 | 4 | #include "ps2_hdd.h" 5 | #define HDL_GAME_NAME_MAX 64 6 | 7 | typedef struct hdl_game_info_type 8 | { 9 | char partition_name[PS2_PART_IDMAX + 1]; 10 | char name[HDL_GAME_NAME_MAX + 1]; 11 | char startup[8 + 1 + 3 + 1]; 12 | u_char compat_flags; 13 | int is_dvd; 14 | u_long start_sector; 15 | u_long total_size_in_kb; 16 | } hdl_game_info_t; 17 | 18 | typedef struct hdl_games_list_type 19 | { 20 | u_long count; 21 | hdl_game_info_t *games; 22 | u_long total_chunks; 23 | u_long free_chunks; 24 | } hdl_games_list_t; 25 | 26 | void hdl_glist_free(hdl_games_list_t *glist); 27 | int hdl_glist_read(hio_t *hio, hdl_games_list_t **glist); 28 | int hdl_glist_write(hio_t *hio, hdl_game_info_t *ginfo); 29 | 30 | #endif /* _CDVDHDL_H_ */ 31 | -------------------------------------------------------------------------------- /docs/SMB2.CNF: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------- 2 | # File name: SMB2.CNF Revision Date: 2020.08.16 3 | # Created by: Ronnie Sahlberg Creation Date: 2020.08.16 4 | # --------------------------------------------------------------------------- 5 | # Purpose: Define SMB2 servers for the SMB2 implementation of wLaunchELF 6 | # --------------------------------------------------------------------------- 7 | NAME = Home-NAS 8 | USERNAME = user 9 | PASSWORD = password 10 | URL = smb://192.168.0.1/Share/ 11 | #---------------------------------------------------------------------------- 12 | #---------------------------------------------------------------------------- 13 | # End of file: SMB.CNF 14 | #---------------------------------------------------------------------------- 15 | -------------------------------------------------------------------------------- /vmc_fs/irx_imports.h: -------------------------------------------------------------------------------- 1 | /* 2 | # _____ ___ ____ ___ ____ 3 | # ____| | ____| | | |____| 4 | # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. 5 | #----------------------------------------------------------------------- 6 | # Copyright (c) 2003 Marcus R. Brown 7 | # Licenced under Academic Free License version 2.0 8 | # Review ps2sdk README & LICENSE files for further details. 9 | # 10 | # $Id: irx_imports.h 377 2004-10-25 15:59:28Z tentacle $ 11 | # Defines all IRX imports. 12 | */ 13 | 14 | #ifndef IOP_IRX_IMPORTS_H 15 | #define IOP_IRX_IMPORTS_H 16 | 17 | #include "irx.h" 18 | 19 | /* Please keep these in alphabetical order! */ 20 | #include "cdvdman.h" 21 | #include "intrman.h" 22 | #include "iomanX.h" 23 | #include "stdio.h" 24 | #include "sysclib.h" 25 | #include "sysmem.h" 26 | 27 | #endif /* IOP_IRX_IMPORTS_H */ 28 | -------------------------------------------------------------------------------- /hdl_info/imports.lst: -------------------------------------------------------------------------------- 1 | atad_IMPORTS_start 2 | I_ata_get_devinfo 3 | I_ata_device_sector_io 4 | I_ata_device_flush_cache 5 | atad_IMPORTS_end 6 | 7 | dev9_IMPORTS_start 8 | I_dev9Shutdown 9 | dev9_IMPORTS_end 10 | 11 | sifcmd_IMPORTS_start 12 | I_sceSifInitRpc 13 | I_sceSifSetRpcQueue 14 | I_sceSifRegisterRpc 15 | I_sceSifRpcLoop 16 | sifcmd_IMPORTS_end 17 | 18 | stdio_IMPORTS_start 19 | I_printf 20 | stdio_IMPORTS_end 21 | 22 | sysclib_IMPORTS_start 23 | I_strcmp 24 | I_strcpy 25 | I_memset 26 | I_memcpy 27 | I_memcmp 28 | sysclib_IMPORTS_end 29 | 30 | sysmem_IMPORTS_start 31 | I_AllocSysMemory 32 | I_FreeSysMemory 33 | sysmem_IMPORTS_end 34 | 35 | thbase_IMPORTS_start 36 | I_GetThreadId 37 | I_CreateThread 38 | I_StartThread 39 | thbase_IMPORTS_end 40 | 41 | intrman_IMPORTS_start 42 | I_CpuSuspendIntr 43 | I_CpuResumeIntr 44 | intrman_IMPORTS_end 45 | 46 | poweroff_IMPORTS_start 47 | I_PoweroffShutdown 48 | poweroff_IMPORTS_end 49 | -------------------------------------------------------------------------------- /hdl_info/irx_imports.h: -------------------------------------------------------------------------------- 1 | /* 2 | # _____ ___ ____ ___ ____ 3 | # ____| | ____| | | |____| 4 | # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. 5 | #----------------------------------------------------------------------- 6 | # Copyright (c) 2003 Marcus R. Brown 7 | # Licenced under Academic Free License version 2.0 8 | # Review ps2sdk README & LICENSE files for further details. 9 | # 10 | # $Id: irx_imports.h 377 2004-10-25 15:59:28Z tentacle $ 11 | # Defines all IRX imports. 12 | */ 13 | 14 | #ifndef IOP_IRX_IMPORTS_H 15 | #define IOP_IRX_IMPORTS_H 16 | 17 | #include 18 | 19 | /* Please keep these in alphabetical order! */ 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #endif /* IOP_IRX_IMPORTS_H */ 31 | -------------------------------------------------------------------------------- /hdl_info/apa.h: -------------------------------------------------------------------------------- 1 | #ifndef _CDVDAPA_H_ 2 | #define _CDVDAPA_H_ 3 | 4 | /* chunks_map */ 5 | static const char MAP_AVAIL = '.'; 6 | static const char MAP_MAIN = 'M'; 7 | static const char MAP_SUB = 's'; 8 | static const char MAP_COLL = 'x'; 9 | static const char MAP_ALLOC = '*'; 10 | 11 | typedef struct apa_partition_type 12 | { 13 | int existing; 14 | int modified; 15 | int linked; 16 | ps2_partition_header_t header; 17 | } apa_partition_t; 18 | 19 | 20 | typedef struct apa_partition_table_type 21 | { 22 | u_long device_size_in_mb; 23 | u_long total_chunks; 24 | u_long allocated_chunks; 25 | u_long free_chunks; 26 | 27 | char *chunks_map; 28 | 29 | /* existing partitions */ 30 | u_long part_alloc_; 31 | u_long part_count; 32 | apa_partition_t *parts; 33 | } apa_partition_table_t; 34 | 35 | void apa_ptable_free(apa_partition_table_t *table); 36 | 37 | u_long apa_partition_checksum(const ps2_partition_header_t *part); 38 | 39 | int apa_ptable_read_ex(hio_t *hio, apa_partition_table_t **table); 40 | 41 | u_long get_u32(const void *buffer); 42 | void set_u32(void *buffer, u_long val); 43 | 44 | u_short get_u16(const void *buffer); 45 | void set_u16(void *buffer, u_short val); 46 | 47 | 48 | #endif /* _APA_H_ */ 49 | -------------------------------------------------------------------------------- /.github/workflows/compilation.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | repository_dispatch: 7 | types: [run_build] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | container: ps2dev/ps2dev:latest 13 | steps: 14 | - name: Install dependencies 15 | run: | 16 | apk add build-base git zip 17 | 18 | - uses: actions/checkout@v2 19 | - run: | 20 | git fetch --prune --unshallow 21 | 22 | - name: Compile wLaunchELF 23 | run: | 24 | make 25 | git ls-files -i --exclude-standard -c 26 | 27 | - name: Get short SHA 28 | id: slug 29 | run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" 30 | 31 | - name: Upload artifacts 32 | if: ${{ success() }} 33 | uses: actions/upload-artifact@v2 34 | with: 35 | name: wLaunchELF-${{ steps.slug.outputs.sha8 }} 36 | path: BOOT.ELF 37 | 38 | - name: Create release 39 | if: github.ref == 'refs/heads/master' 40 | uses: marvinpinto/action-automatic-releases@latest 41 | with: 42 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 43 | automatic_release_tag: "latest" 44 | title: "Latest development build" 45 | files: BOOT.ELF 46 | -------------------------------------------------------------------------------- /nfs.h: -------------------------------------------------------------------------------- 1 | /* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ 2 | //--------------------------------------------------------------------------- 3 | //File name: nfs.h 4 | //--------------------------------------------------------------------------- 5 | struct nfs_share { 6 | struct nfs_share *next; 7 | struct nfs_context *nfs; 8 | char *name; 9 | char *url; 10 | }; 11 | 12 | extern struct nfs_share *nfs_shares; 13 | 14 | int init_nfs(const char *ip, const char *netmask, const char *gw); 15 | void deinit_nfs(void); 16 | 17 | struct NFSFH { 18 | struct nfs_context *nfs; 19 | struct nfsfh *fh; 20 | }; 21 | 22 | struct NFSFH *NFSopen(const char *path, int mode); 23 | int NFSlseek(struct NFSFH *fh, int where, int how); 24 | int NFSread(struct NFSFH *fh, char *buf, int size); 25 | int NFSwrite(struct NFSFH *fh, char *buf, int size); 26 | int NFSclose(struct NFSFH *fh); 27 | 28 | int readNFS(const char *path, FILEINFO *info, int max); 29 | int NFSmkdir(const char *dir, int fileMode); 30 | int NFSrmdir(const char *dir); 31 | int NFSunlink(const char *dir); 32 | int NFSrename(const char *path, const char *newpath); 33 | 34 | //--------------------------------------------------------------------------- 35 | //End of file: nfs.h 36 | //--------------------------------------------------------------------------- 37 | -------------------------------------------------------------------------------- /smb2.h: -------------------------------------------------------------------------------- 1 | /* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ 2 | //--------------------------------------------------------------------------- 3 | //File name: smb2.h 4 | //--------------------------------------------------------------------------- 5 | struct smb2_share { 6 | struct smb2_share *next; 7 | struct smb2_context *smb2; 8 | char *name; 9 | const char *user; 10 | const char *password; 11 | char *url; 12 | }; 13 | 14 | extern struct smb2_share *smb2_shares; 15 | 16 | int init_smb2(const char *ip, const char *netmask, const char *gw); 17 | void deinit_smb2(void); 18 | int readSMB2(const char *path, FILEINFO *info, int max); 19 | int SMB2mkdir(const char *dir, int fileMode); 20 | int SMB2rmdir(const char *dir); 21 | int SMB2unlink(const char *dir); 22 | int SMB2rename(const char *path, const char *newpath); 23 | 24 | struct SMB2FH { 25 | struct smb2_context *smb2; 26 | struct smb2fh *fh; 27 | }; 28 | struct SMB2FH *SMB2open(const char *path, int mode); 29 | int SMB2close(struct SMB2FH *fh); 30 | int SMB2read(struct SMB2FH *fh, char *buf, int size); 31 | int SMB2write(struct SMB2FH *fh, char *buf, int size); 32 | int SMB2lseek(struct SMB2FH *fh, int where, int how); 33 | 34 | //--------------------------------------------------------------------------- 35 | //End of file: smb2.h 36 | //--------------------------------------------------------------------------- 37 | -------------------------------------------------------------------------------- /loader/linkfile: -------------------------------------------------------------------------------- 1 | ENTRY(__start); 2 | 3 | MEMORY { 4 | bios : ORIGIN = 0x00000000, LENGTH = 528K /* 0x00000000 - 0x00084000: BIOS memory */ 5 | bram : ORIGIN = 0x00084000, LENGTH = 496K /* 0x00084000 - 0x00100000: BIOS unused memory */ 6 | gram : ORIGIN = 0x00100000, LENGTH = 31M /* 0x00100000 - 0x02000000: GAME memory */ 7 | } 8 | 9 | REGION_ALIAS("MAIN_REGION", bram); 10 | 11 | PHDRS { 12 | text PT_LOAD; 13 | } 14 | 15 | SECTIONS { 16 | .text : { 17 | *(.text) 18 | } >MAIN_REGION :text 19 | 20 | .reginfo : { *(.reginfo) } >MAIN_REGION 21 | 22 | .ctors ALIGN(16): { 23 | KEEP(*crtbegin*.o(.ctors)) 24 | KEEP(*(EXCLUDE_FILE(*crtend*.o) .ctors)) 25 | KEEP(*(SORT(.ctors.*))) 26 | KEEP(*(.ctors)) 27 | } >MAIN_REGION 28 | 29 | .dtors ALIGN(16): { 30 | KEEP(*crtbegin*.o(.dtors)) 31 | KEEP(*(EXCLUDE_FILE(*crtend*.o) .dtors)) 32 | KEEP(*(SORT(.dtors.*))) 33 | KEEP(*(.dtors)) 34 | } >MAIN_REGION 35 | 36 | .rodata ALIGN(128): { 37 | *(.rodata) 38 | } >MAIN_REGION 39 | 40 | .data ALIGN(128): { 41 | _fdata = . ; 42 | *(.data) 43 | SORT(CONSTRUCTORS) 44 | } >MAIN_REGION 45 | 46 | _gp = ALIGN(128) + 0x7ff0; 47 | .lit4 ALIGN(128): { *(.lit4) } >MAIN_REGION 48 | .lit8 ALIGN(128): { *(.lit8) } >MAIN_REGION 49 | 50 | .sdata ALIGN(128): { 51 | *(.sdata) 52 | } >MAIN_REGION 53 | 54 | .sbss ALIGN(128) : { 55 | _fbss = . ; 56 | *(.sbss) 57 | } >MAIN_REGION 58 | 59 | .bss ALIGN(128) : { 60 | *(.bss) 61 | } >MAIN_REGION 62 | 63 | /* Symbols needed by crt0.s. */ 64 | PROVIDE(_end = .); 65 | PROVIDE(_heap_size = -1); 66 | 67 | PROVIDE(_stack = .); 68 | PROVIDE(_stack_size = ORIGIN(MAIN_REGION) + LENGTH(MAIN_REGION) - _stack); 69 | } 70 | -------------------------------------------------------------------------------- /hdl_rpc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "launchelf.h" 9 | 10 | static SifRpcClientData_t client __attribute__((aligned(64))); 11 | static int Rpc_Buffer[1024] __attribute__((aligned(64))); 12 | 13 | typedef struct 14 | { 15 | char Partition_Name[32 + 1]; 16 | } Rpc_Packet_Send_GetInfo; 17 | 18 | typedef struct 19 | { 20 | char OldName[64]; 21 | char NewName[64]; 22 | } Rpc_Packet_Send_Rename; 23 | 24 | int Hdl_Inited = 0; 25 | 26 | int Hdl_Info_BindRpc() 27 | { 28 | int ret; 29 | int retryCount = 0x1000; 30 | 31 | while (retryCount--) { 32 | ret = SifBindRpc(&client, HDL_IRX, 0); 33 | if (ret < 0) { 34 | printf("Hdl Info: EE Bind RPC Error.\n"); 35 | return -1; 36 | } 37 | if (client.server != 0) { 38 | printf("Hdl Info: EE Bind RPC Set.\n"); 39 | break; 40 | } 41 | 42 | // short delay 43 | ret = 0x10000; 44 | while (ret--) 45 | asm("nop\nnop\nnop\nnop"); 46 | } 47 | 48 | Hdl_Inited = 1; 49 | return retryCount; 50 | } 51 | 52 | int HdlGetGameInfo(char *PartName, GameInfo *Game) 53 | { 54 | 55 | Rpc_Packet_Send_GetInfo *Packet = (Rpc_Packet_Send_GetInfo *)Rpc_Buffer; 56 | 57 | if (!Hdl_Inited) 58 | return -1; 59 | 60 | strcpy(Packet->Partition_Name, PartName); 61 | 62 | SifCallRpc(&client, HDL_GETINFO, 0, (void *)Rpc_Buffer, sizeof(Rpc_Packet_Send_GetInfo), (void *)Rpc_Buffer, sizeof(GameInfo) + 4, 0, 0); 63 | 64 | memcpy(Game, ((void *)Rpc_Buffer) + 4, sizeof(GameInfo)); 65 | 66 | return Rpc_Buffer[0]; 67 | } 68 | 69 | int HdlRenameGame(char *OldName, char *NewName) 70 | { 71 | 72 | Rpc_Packet_Send_Rename *Packet = (Rpc_Packet_Send_Rename *)Rpc_Buffer; 73 | 74 | if (!Hdl_Inited) 75 | return -1; 76 | 77 | strcpy(Packet->OldName, OldName); 78 | strcpy(Packet->NewName, NewName); 79 | 80 | SifCallRpc(&client, HDL_RENAME, 0, (void *)(Rpc_Buffer), sizeof(Rpc_Packet_Send_Rename), (void *)Rpc_Buffer, 4, 0, 0); 81 | 82 | return Rpc_Buffer[0]; 83 | } 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CI](https://github.com/ps2homebrew/wLaunchELF/workflows/CI/badge.svg)](https://github.com/ps2homebrew/wLaunchELF/actions?query=workflow%3ACI) 2 | 3 | # smbLaunchELF 4 | This is a special version of LaunchELF that has support for SMB2/3 and NFS. 5 | It can connect to Windows/Samba/Azure file shares and supports up to 6 | version 3.1.1 of SMB. 7 | It can connect to NFSv3 and v4 servers. 8 | The main purpose for this version is just to copy files to/from SMB2 and/or NFS 9 | file servers to avoid having to use clunky FTP. 10 | 11 | To build this version you need to install LIBSMB2 and LIBNFS for PS2 EE. 12 | See hompage for libsmb2, libnfs for instructions on how to build and install 13 | them in ps2dev. 14 | 15 | SMB2 16 | ==== 17 | You can specify SMB2 servers and shares in either of the files: 18 | mc0:/SYS-CONF/SMB2.CNF or 19 | mc1:/SYS-CONF/SMB2.CNF or 20 | mass:/SYS-CONF/SMB2.CNF 21 | 22 | The format of this file is : 23 | 24 | NAME = Home-NAS 25 | 26 | USERNAME = user 27 | 28 | PASSWORD = password 29 | 30 | URL = smb://192.168.0.1/Share/ 31 | 32 | For each such entry an new subdirectory will appear under the smb2: device at 33 | the root in the file manager. 34 | It can copy files to/from smb2 shares and the ps2. 35 | 36 | Even use SMB3.1.1 encryption to Azure cloud shares. Wooohooo 37 | 38 | 39 | NFS 40 | === 41 | You can specify NFS servers and shares in either of the files: 42 | mc0:/SYS-CONF/NFS.CNF or 43 | mc1:/SYS-CONF/NFS.CNF or 44 | mass:/SYS-CONF/NFS.CNF 45 | 46 | The format of this file is : 47 | 48 | NAME = Home-NFS 49 | 50 | URL = nfs://192.168.0.1/path/export 51 | 52 | For each such entry an new subdirectory will appear under the nfs: device at 53 | the root in the file manager. 54 | See libnfs README file for optional URL arguments, such as selecting NFSv4. 55 | 56 | # wLaunchELF 57 | 58 | wLaunchELF, formerly known as uLaunchELF, also known as wLE or uLE (abbreviated), is an open-source file manager and executable launcher for the Playstation 2 console based on the original LaunchELF. It contains many different features, including a text editor, hard drive manager, FTP support, and much more. 59 | -------------------------------------------------------------------------------- /chkesr.c: -------------------------------------------------------------------------------- 1 | /* 2 | _____ ___ ____ 3 | ____| | ____| PS2 Open Source Project 4 | | ___| |____ 5 | 6 | --------------------------------------------------------------------------- 7 | 8 | Copyright (C) 2008 - Neme & jimmikaelkael (www.psx-scene.com) 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the Free McBoot License. 12 | 13 | This program and any related documentation is provided "as is" 14 | WITHOUT ANY WARRANTIES, either express or implied, including, but not 15 | limited to, implied warranties of fitness for a particular purpose. The 16 | entire risk arising out of use or performance of the software remains 17 | with you. 18 | In no event shall the author be liable for any damages whatsoever 19 | (including, without limitation, damages to your hardware or equipment, 20 | environmental damage, loss of health, or any kind of pecuniary loss) 21 | arising out of the use of or inability to use this software or 22 | documentation, even if the author has been advised of the possibility of 23 | such damages. 24 | 25 | You should have received a copy of the Free McBoot License along with 26 | this program; if not, please report at psx-scene : 27 | http://psx-scene.com/forums/freevast/ 28 | 29 | --------------------------------------------------------------------------- 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | int Check_ESR_Disc(void) 39 | { 40 | sceCdRMode ReadMode; 41 | int result; 42 | unsigned char SectorBuffer[2112]; 43 | 44 | ReadMode.trycount = 5; 45 | ReadMode.spindlctrl = SCECdSpinNom; 46 | ReadMode.datapattern = SCECdSecS2048; 47 | ReadMode.pad = 0; 48 | 49 | result = sceCdReadDVDV(14, 1, SectorBuffer, &ReadMode); // read LBA 14 50 | sceCdSync(0); 51 | if (result != 0) { 52 | if (sceCdGetError() == SCECdErNO) { 53 | result = (!strncmp(SectorBuffer + 37, "+NSR", 4)) ? 1 : 0; 54 | } else 55 | result = -1; 56 | } else 57 | result = -1; 58 | 59 | return result; 60 | } 61 | -------------------------------------------------------------------------------- /hdl_info/hdd.h: -------------------------------------------------------------------------------- 1 | #ifndef _CDVDHDD_H_ 2 | #define _CDVDHDD_H_ 3 | 4 | #define HDL_IRX 0xD0D0D0D 5 | 6 | #define HDD_SECTOR_SIZE 512 /* HDD sector size in bytes */ 7 | 8 | /* HD Loader I/O interface */ 9 | 10 | typedef struct hio_type hio_t; 11 | 12 | typedef int (*hio_probe_t)(const char *path, 13 | hio_t **hio); 14 | 15 | typedef int (*hio_stat_t)(hio_t *hio, 16 | u_long *size_in_kb); 17 | 18 | typedef int (*hio_read_t)(hio_t *hio, 19 | u_long start_sector, 20 | u_long num_sectors, 21 | void *output, 22 | u_long *bytes); 23 | 24 | typedef int (*hio_write_t)(hio_t *hio, 25 | u_long start_sector, 26 | u_long num_sectors, 27 | const void *input, 28 | u_long *bytes); 29 | 30 | typedef int (*hio_flush_t)(hio_t *hio); 31 | 32 | typedef int (*hio_poweroff_t)(hio_t *hio); 33 | 34 | typedef int (*hio_close_t)(hio_t *hio); 35 | 36 | /* return last error text in a memory buffer, that would be freed by calling hio_dispose_error_t */ 37 | typedef char *(*hio_last_error_t)(hio_t *hio); 38 | typedef void (*hio_dispose_error_t)(hio_t *hio, 39 | char *error); 40 | 41 | struct hio_type 42 | { 43 | hio_stat_t stat; 44 | hio_read_t read; 45 | hio_write_t write; 46 | hio_flush_t flush; 47 | hio_close_t close; 48 | hio_poweroff_t poweroff; 49 | hio_last_error_t last_error; 50 | hio_dispose_error_t dispose_error; 51 | }; 52 | 53 | typedef struct hio_iop_type 54 | { 55 | hio_t hio; 56 | int unit; 57 | size_t size_in_sectors; 58 | } hio_iop_t; 59 | 60 | typedef struct 61 | { 62 | char Partition_Name[32 + 1]; 63 | } Rpc_Packet_Send_GetInfo; 64 | 65 | typedef struct 66 | { 67 | char OldName[64]; 68 | char NewName[64]; 69 | } Rpc_Packet_Send_Rename; 70 | 71 | typedef struct 72 | { 73 | char Partition_Name[32 + 1]; 74 | char Name[64 + 1]; 75 | char Startup[8 + 1 + 3 + 1]; 76 | int Is_Dvd; 77 | } GameInfo; 78 | 79 | int HdlGetGameInfo(char *PartName, GameInfo *GameInf); 80 | int HdlRenameGame(void *Data); 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /loader/Rules.make: -------------------------------------------------------------------------------- 1 | # _____ ___ ____ ___ ____ 2 | # ____| | ____| | | |____| 3 | # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. 4 | #----------------------------------------------------------------------- 5 | # Copyright 2001-2004, ps2dev - http://www.ps2dev.org 6 | # Licenced under Academic Free License version 2.0 7 | # Review ps2sdk README & LICENSE files for further details. 8 | 9 | EE_CC_VERSION := $(shell $(EE_CC) --version 2>&1 | sed -n 's/^.*(GCC) //p') 10 | 11 | # Helpers to make easy the use of lkernel-nopatch and newlib-nano 12 | NODEFAULTLIBS = 0 13 | LKERNEL = -lkernel 14 | ifeq ($(KERNEL_NOPATCH), 1) 15 | NODEFAULTLIBS = 1 16 | LKERNEL = -lkernel-nopatch 17 | endif 18 | 19 | LIBC = -lc 20 | LIBM = -lm 21 | ifeq ($(NEWLIB_NANO), 1) 22 | NODEFAULTLIBS = 1 23 | LIBC = -lc_nano 24 | LIBM = -lm_nano 25 | endif 26 | 27 | EXTRA_LDFLAGS = 28 | ifeq ($(NODEFAULTLIBS), 1) 29 | EXTRA_LDFLAGS = -nodefaultlibs $(LIBM) -Wl,--start-group $(LIBC) -lps2sdkc $(LKERNEL) -Wl,--end-group -lgcc 30 | endif 31 | 32 | # Include directories 33 | EE_INCS := -I$(PS2SDK)/ee/include -I$(PS2SDK)/common/include -I. $(EE_INCS) 34 | 35 | # C compiler flags 36 | EE_CFLAGS := -D_EE -O2 -G0 -Wall $(EE_CFLAGS) 37 | 38 | # C++ compiler flags 39 | EE_CXXFLAGS := -D_EE -O2 -G0 -Wall $(EE_CXXFLAGS) 40 | 41 | # Linker flags 42 | EE_LDFLAGS := -L$(PS2SDK)/ee/lib -Wl,-zmax-page-size=128 $(EXTRA_LDFLAGS) $(EE_LDFLAGS) 43 | 44 | # Assembler flags 45 | EE_ASFLAGS := -G0 $(EE_ASFLAGS) 46 | 47 | # Externally defined variables: EE_BIN, EE_OBJS, EE_LIB 48 | 49 | # These macros can be used to simplify certain build rules. 50 | EE_C_COMPILE = $(EE_CC) $(EE_CFLAGS) $(EE_INCS) 51 | EE_CXX_COMPILE = $(EE_CXX) $(EE_CXXFLAGS) $(EE_INCS) 52 | 53 | %.o: %.c 54 | $(EE_CC) $(EE_CFLAGS) $(EE_INCS) -c $< -o $@ 55 | 56 | %.o: %.cc 57 | $(EE_CXX) $(EE_CXXFLAGS) $(EE_INCS) -c $< -o $@ 58 | 59 | %.o: %.cpp 60 | $(EE_CXX) $(EE_CXXFLAGS) $(EE_INCS) -c $< -o $@ 61 | 62 | %.o: %.S 63 | $(EE_CC) $(EE_CFLAGS) $(EE_INCS) -c $< -o $@ 64 | 65 | %.o: %.s 66 | $(EE_AS) $(EE_ASFLAGS) $< -o $@ 67 | 68 | $(EE_BIN): $(EE_OBJS) 69 | $(EE_CC) $(EE_CFLAGS) -o $(EE_BIN) $(EE_OBJS) $(EE_LDFLAGS) $(EE_LIBS) 70 | 71 | $(EE_ERL): $(EE_OBJS) 72 | $(EE_CC) -o $(EE_ERL) $(EE_OBJS) $(EE_CFLAGS) $(EE_LDFLAGS) -Wl,-r -Wl,-d 73 | $(EE_STRIP) --strip-unneeded -R .mdebug.eabi64 -R .reginfo -R .comment $(EE_ERL) 74 | 75 | $(EE_LIB): $(EE_OBJS) 76 | $(EE_AR) cru $(EE_LIB) $(EE_OBJS) 77 | -------------------------------------------------------------------------------- /docs/keyboard.txt: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------- 2 | // File name: keyboard.txt 3 | //-------------------------------------------------------------- 4 | From version v3.65 uLaunchELF supports use of USB keyboard, both for entry of 5 | file and folder names, and for general control and navigation, in which the 6 | keyboard can be used as a replacement for the gamepad. In fact you can use 7 | either gamepad in parallel with the keyboard too. That's entirely up to you, 8 | as all three controllers remain active at once in uLaunchELF. 9 | 10 | When used for entry of file/folder names, the following 'mapping' applies: 11 | 12 | KB_Left => Move cursor left 13 | KB_Right => Move cursor right 14 | KB_Backspace => Delete character to the left (if any) and move cursor there 15 | KB_Delete => Delete character to the right (if any) 16 | KB_Home => Move cursor to start of string 17 | KB_End => Move cursor to end of string 18 | KB_Escape => End entry dialog as Canceled (new string will not be used) 19 | KB_Enter => End entry dialog as OK (new string will be used) 20 | 21 | The mapping described above takes precedence over the one described below, 22 | so when entering file/folder names the mapping described below is not used. 23 | 24 | When used as generic controller most gamepad buttons have more than one 25 | equivalent key on the keyboard. This is because many different keyboard 26 | types exist, and different users have different preferences. Hopefully 27 | most users will find at least one of the available button sets convenient. 28 | 29 | L1 == KB_F1 or '1' R1 == KB_F12 or '0' 30 | L2 == KB_F2 or '2' R2 == KB_F11 or '9' 31 | L3 == KB_F3 or '3' R3 == KB_F10 or '8' 32 | Up == KB_Up or 'w' Triangle== KB_Home or 'i' or KB_Escape 33 | Left == KB_Left or 'a' Square == KB_End or 'j' 34 | Right == KB_Right or 's' Circle == KB_PgUp or 'k' 35 | Down == KB_Down or 'z' Cross == KB_PgDn or 'm' 36 | Select== KB_Insert Start == KB_Delete 37 | 38 | In addition to the above, two keys are mapped differently depending on 39 | the button mapping you have chosen for Circle/Cross in uLaunchELF. 40 | 41 | KB_Enter will mean OK/Activate 42 | KB_Space will mean Cancel/Mark 43 | 44 | //-------------------------------------------------------------- 45 | // End of file: keyboard.txt 46 | //-------------------------------------------------------------- 47 | 48 | -------------------------------------------------------------------------------- /hdl_info/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "main.h" 12 | #include "ps2_hdd.h" 13 | #include "hdd.h" 14 | 15 | int __attribute__((unused)) shutdown() { return 0; } 16 | 17 | /* function declaration */ 18 | void rpcMainThread(void *param); 19 | void *rpcCommandHandler(int command, void *Data, int Size); 20 | 21 | static SifRpcDataQueue_t Rpc_Queue __attribute__((aligned(64))); 22 | static SifRpcServerData_t Rpc_Server __attribute((aligned(64))); 23 | static int Rpc_Buffer[1024] __attribute((aligned(64))); 24 | 25 | /* Description: Module entry point */ 26 | int _start(int argc, char **argv) 27 | { 28 | iop_thread_t param; 29 | int id; 30 | 31 | printf("Hdl Info: PS2 HDLoader Information Module v 0.1\n"); 32 | printf("Hdl Info: 2006 Polo\n"); 33 | 34 | printf("Hdl Info: IOP RPC Initialization.\n"); 35 | /*create thread*/ 36 | param.attr = TH_C; 37 | param.thread = rpcMainThread; 38 | param.priority = 40; 39 | param.stacksize = 0x800; 40 | param.option = 0; 41 | 42 | id = CreateThread(¶m); 43 | if (id > 0) { 44 | StartThread(id, 0); 45 | return 0; 46 | } else 47 | return 1; 48 | 49 | return MODULE_RESIDENT_END; 50 | } 51 | 52 | void rpcMainThread(void *param) 53 | { 54 | SifInitRpc(0); 55 | SifSetRpcQueue(&Rpc_Queue, GetThreadId()); 56 | SifRegisterRpc(&Rpc_Server, HDL_IRX, (void *)rpcCommandHandler, (u8 *)&Rpc_Buffer, 0, 0, &Rpc_Queue); 57 | SifRpcLoop(&Rpc_Queue); 58 | } 59 | 60 | void *rpcCommandHandler(int command, void *Data, int Size) 61 | { 62 | switch (command) { 63 | case 4: //HDL Get Game Info 64 | ((int *)Data)[0] = HdlGetGameInfo((char *)Data, (GameInfo *)(Data + 4)); 65 | break; 66 | case 5: //HDL Rename Game 67 | ((int *)Data)[0] = HdlRenameGame((char *)Data); 68 | break; 69 | default: 70 | break; 71 | } 72 | return Data; 73 | } 74 | 75 | void *malloc(int size) 76 | { 77 | int OldState; 78 | void *result; 79 | 80 | CpuSuspendIntr(&OldState); 81 | result = AllocSysMemory(ALLOC_FIRST, size, NULL); 82 | CpuResumeIntr(OldState); 83 | 84 | return result; 85 | } 86 | 87 | void free(void *ptr) 88 | { 89 | int OldState; 90 | 91 | CpuSuspendIntr(&OldState); 92 | FreeSysMemory(ptr); 93 | CpuResumeIntr(OldState); 94 | } 95 | -------------------------------------------------------------------------------- /hdl_info/ps2_hdd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ps2_hdd.h 3 | * $Id: ps2_hdd.h,v 1.5 2005/07/10 21:06:48 bobi Exp $ 4 | * 5 | * borrowed from ps2fdisk 6 | */ 7 | 8 | #ifndef _PS2_HDD_H_ 9 | #define _PS2_HDD_H_ 10 | 11 | typedef unsigned char u_char; 12 | typedef unsigned int u_int; 13 | typedef unsigned short u_short; 14 | typedef unsigned long u_long; 15 | 16 | /* Various PS2 partition constants */ 17 | #define PS2_PARTITION_MAGIC "APA" /* "APA\0" */ 18 | #define PS2_PART_IDMAX 32 19 | #define PS2_PART_NAMEMAX 32 20 | #define PS2_PART_MAXSUB 64 /* Maximum # of sub-partitions */ 21 | #define PS2_PART_FLAG_SUB 0x0001 /* Is partition a sub-partition? */ 22 | #define PS2_MBR_VERSION 2 /* Current MBR version */ 23 | 24 | /* Partition types */ 25 | #define PS2_MBR_PARTITION 0x0001 26 | #define PS2_SWAP_PARTITION 0x0082 27 | #define PS2_LINUX_PARTITION 0x0083 28 | #define PS2_GAME_PARTITION 0x0100 29 | 30 | /* Date/time descriptor used in on-disk partition header */ 31 | typedef struct ps2fs_datetime_type 32 | { 33 | u_char unused; 34 | u_char sec; 35 | u_char min; 36 | u_char hour; 37 | u_char day; 38 | u_char month; 39 | u_short year; 40 | } ps2fs_datetime_t; 41 | 42 | /* On-disk partition header for a partition */ 43 | typedef struct ps2_partition_header_type 44 | { 45 | u_long checksum; /* Sum of all 256 words, assuming checksum==0 */ 46 | u_char magic[4]; /* PS2_PARTITION_MAGIC */ 47 | u_long next; /* Sector address of next partition */ 48 | u_long prev; /* Sector address of previous partition */ 49 | char id[PS2_PART_IDMAX]; 50 | char unknown1[16]; 51 | u_long start; /* Sector address of this partition */ 52 | u_long length; /* Sector count */ 53 | u_short type; 54 | u_short flags; /* PS2_PART_FLAG_* */ 55 | u_long nsub; /* No. of sub-partitions (stored in main partition) */ 56 | ps2fs_datetime_t created; 57 | u_long main; /* For sub-partitions, main partition sector address */ 58 | u_long number; /* For sub-partitions, sub-partition number */ 59 | u_short unknown2; 60 | char unknown3[30]; 61 | char name[PS2_PART_NAMEMAX]; 62 | struct 63 | { 64 | char magic[32]; /* Copyright message in MBR */ 65 | char unknown_0x02; 66 | char unknown1[7]; 67 | ps2fs_datetime_t created; /* Same as for the partition, it seems*/ 68 | u_long data_start; /* Some sort of MBR data; position in sectors*/ 69 | u_long data_len; /* Length also in sectors */ 70 | char unknown2[200]; 71 | } mbr; 72 | struct 73 | { /* Sub-partition data */ 74 | u_long start; /* Sector address */ 75 | u_long length; /* Sector count */ 76 | } subs[PS2_PART_MAXSUB]; 77 | } ps2_partition_header_t; 78 | 79 | #endif /* _PS2_HDD_H_ */ 80 | -------------------------------------------------------------------------------- /AllowDVDV/AllowDVDV.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MODNAME "AllowDVDV" 6 | IRX_ID(MODNAME, 1, 4); 7 | 8 | static u8 buf[137] __attribute((aligned(16))); 9 | 10 | static u8 psxver[11] __attribute((aligned(16))) = "rom0:PSXVER"; 11 | 12 | 13 | // clang-format off 14 | static u8 Header[32] __attribute((aligned(16))) = {0x01, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x4A, 0x00, 0x01, 0x02, 0x19, 0x00, 0x00, 0x00, 0x56, 15 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x07, 0x2C, 0x02, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00}; 16 | 17 | 18 | 19 | static u8 ps2Part1[8] __attribute((aligned(16))) = {0xFA, 0xA2, 0x47, 0xE9, 0xFA, 0x20, 0x89, 0x19}; 20 | static u8 ps2Part2[49] __attribute((aligned(16))) = { 21 | 0x25, 0xD1, 0x26, 0x8E, 0x3E, 0xB5, 0x38, 0xC2, 22 | 0x87, 0xC0, 0xA9, 0xD6, 0xD5, 0x7B, 0x56, 0x87, 0x7B, 0x95, 0x6E, 0x17, 0xF6, 0xBD, 0x76, 0x51, 23 | 0xB8, 0x5D, 0x0D, 0x6F, 0x3C, 0x7F, 0x51, 0x5A, 0xC2, 0xC7, 0x53, 0x3B, 0x46, 0x8E, 0x0C, 0x04, 24 | 0x00, 0x94, 0xF6, 0xB2, 0x6D, 0xA8, 0x8F, 0x76, 0x96, 25 | }; 26 | 27 | 28 | static u8 psxPart1[8] __attribute((aligned(16))) = {0x98, 0xF7, 0x5C, 0x84, 0x38, 0xC5, 0xBD, 0x3C}; 29 | static u8 psxPart2[49] __attribute((aligned(16))) = { 30 | 0x2F, 0xDC, 0xA6, 0x35, 0x8D, 0xE7, 0x5B, 0x77, 31 | 0x02, 0x47, 0xD9, 0xD2, 0x6E, 0xCC, 0x4D, 0x60, 0x07, 0xBC, 0xCC, 0x1A, 0x7C, 0x55, 0x0E, 0x48, 32 | 0x91, 0x64, 0x3B, 0xAA, 0xB9, 0x16, 0x6E, 0x09, 0x6E, 0xDD, 0xA4, 0x2B, 0x19, 0x37, 0x20, 0x79, 33 | 0x00, 0xBF, 0x0D, 0x19, 0x40, 0xDA, 0xB1, 0x99, 0xFF, 34 | }; 35 | 36 | static u8 CT[16] __attribute((aligned(16))) = { 37 | 0xDE, 0xF0, 0x76, 0x8C, 0x1B, 0x36, 0xF8, 0x07, 38 | 0xE0, 0x4B, 0x39, 0x33, 0xF9, 0x6D, 0x4F, 0xFF, 39 | }; 40 | // clang-format on 41 | 42 | 43 | int _start() 44 | { 45 | register int file; 46 | 47 | memset(buf, 0, 137); 48 | 49 | memcpy(buf, Header, 32); 50 | memcpy(buf + 48, psxver, 11); 51 | 52 | if ((file = open((char *)buf + 48, O_RDONLY)) <= 0) { 53 | buf[16] = 0xC0; 54 | buf[17] = 0xF9; 55 | 56 | memcpy(buf + 32, ps2Part1, 8); 57 | memcpy(buf + 88, ps2Part2, 49); 58 | } else { 59 | close(file); 60 | buf[16] = 0x90; 61 | buf[17] = 0xCC; 62 | buf[18] = 0x01; 63 | buf[22] = 0x01; 64 | memcpy(buf + 32, psxPart1, 8); 65 | memcpy(buf + 88, psxPart2, 49); 66 | } 67 | memcpy(buf + 72, CT, 16); 68 | 69 | memset(ps2Part1, 0, 8); 70 | memset(ps2Part2, 0, 49); 71 | memset(psxPart1, 0, 8); 72 | memset(psxPart2, 0, 49); 73 | memset(CT, 0, 16); 74 | 75 | SecrDiskBootFile(buf); 76 | 77 | memset(buf, 0, 137); 78 | 79 | return 0; 80 | } 81 | //------------------------------------------------------------------------- 82 | DECLARE_IMPORT_TABLE(secrman, 1, 0) 83 | DECLARE_IMPORT(13, SecrDiskBootFile) 84 | END_IMPORT_TABLE 85 | -------------------------------------------------------------------------------- /Rules.make: -------------------------------------------------------------------------------- 1 | # _____ ___ ____ ___ ____ 2 | # ____| | ____| | | |____| 3 | # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. 4 | #----------------------------------------------------------------------- 5 | # Copyright 2001-2004, ps2dev - http://www.ps2dev.org 6 | # Licenced under Academic Free License version 2.0 7 | # Review ps2sdk README & LICENSE files for further details. 8 | # 9 | # $Id$ 10 | 11 | 12 | IOP_CC_VERSION := $(shell $(IOP_CC) -dumpversion) 13 | 14 | ASFLAGS_TARGET = -mcpu=r3000 15 | 16 | ifeq ($(IOP_CC_VERSION),3.2.2) 17 | ASFLAGS_TARGET = -march=r3000 18 | endif 19 | 20 | ifeq ($(IOP_CC_VERSION),3.2.3) 21 | ASFLAGS_TARGET = -march=r3000 22 | endif 23 | 24 | IOP_INCS := $(IOP_INCS) -I$(PS2SDK)/iop/include -I$(PS2SDK)/common/include -Iinclude 25 | 26 | IOP_CFLAGS := -D_IOP -fno-builtin -O2 -G0 $(IOP_INCS) $(IOP_CFLAGS) 27 | IOP_ASFLAGS := $(ASFLAGS_TARGET) -EL -G0 $(IOP_ASFLAGS) 28 | IOP_LDFLAGS := -nostdlib $(IOP_LDFLAGS) 29 | 30 | BIN2C = $(PS2SDK)/bin/bin2c 31 | BIN2S = $(PS2SDK)/bin/bin2s 32 | BIN2O = $(PS2SDK)/bin/bin2o 33 | 34 | # Externally defined variables: IOP_BIN, IOP_OBJS, IOP_LIB 35 | 36 | %.o : %.c 37 | $(IOP_CC) $(IOP_CFLAGS) -c $< -o $@ 38 | 39 | %.o : %.S 40 | $(IOP_CC) $(IOP_CFLAGS) $(IOP_INCS) -c $< -o $@ 41 | 42 | %.o : %.s 43 | $(IOP_AS) $(IOP_ASFLAGS) $< -o $@ 44 | 45 | #Rules for the PS2SDK-styled projects (objects in objs/, binary in bin/) 46 | $(IOP_OBJS_DIR)%.o : $(IOP_SRC_DIR)%.c 47 | $(IOP_CC) $(IOP_CFLAGS) -c $< -o $@ 48 | 49 | $(IOP_OBJS_DIR)%.o : $(IOP_SRC_DIR)%.S 50 | $(IOP_CC) $(IOP_CFLAGS) $(IOP_INCS) -c $< -o $@ 51 | 52 | $(IOP_OBJS_DIR)%.o : $(IOP_SRC_DIR)%.s 53 | $(IOP_AS) $(IOP_ASFLAGS) $< -o $@ 54 | 55 | # A rule to build imports.lst. 56 | $(IOP_OBJS_DIR)%.o : $(IOP_SRC_DIR)%.lst 57 | $(ECHO) "#include \"irx_imports.h\"" > $(IOP_OBJS_DIR)build-imports.c 58 | cat $< >> $(IOP_OBJS_DIR)build-imports.c 59 | $(IOP_CC) $(IOP_CFLAGS) -I$(IOP_SRC_DIR) -c $(IOP_OBJS_DIR)build-imports.c -o $@ 60 | -rm -f $(IOP_OBJS_DIR)build-imports.c 61 | 62 | # A rule to build exports.tab. 63 | $(IOP_OBJS_DIR)%.o : $(IOP_SRC_DIR)%.tab 64 | $(ECHO) "#include \"irx.h\"" > $(IOP_OBJS_DIR)build-exports.c 65 | cat $< >> $(IOP_OBJS_DIR)build-exports.c 66 | $(IOP_CC) $(IOP_CFLAGS) -I$(IOP_SRC_DIR) -c $(IOP_OBJS_DIR)build-exports.c -o $@ 67 | -rm -f $(IOP_OBJS_DIR)build-exports.c 68 | 69 | $(IOP_OBJS_DIR): 70 | $(MKDIR) -p $(IOP_OBJS_DIR) 71 | 72 | $(IOP_BIN_DIR): 73 | $(MKDIR) -p $(IOP_BIN_DIR) 74 | 75 | $(IOP_LIB_DIR): 76 | $(MKDIR) -p $(IOP_LIB_DIR) 77 | 78 | # A rule to build imports.lst. 79 | %.o : %.lst 80 | $(ECHO) "#include \"irx_imports.h\"" > build-imports.c 81 | cat $< >> build-imports.c 82 | $(IOP_CC) $(IOP_CFLAGS) -I. -c build-imports.c -o $@ 83 | -rm -f build-imports.c 84 | 85 | # A rule to build exports.tab. 86 | %.o : %.tab 87 | $(ECHO) "#include \"irx.h\"" > build-exports.c 88 | cat $< >> build-exports.c 89 | $(IOP_CC) $(IOP_CFLAGS) -I. -c build-exports.c -o $@ 90 | -rm -f build-exports.c 91 | 92 | $(IOP_BIN) : $(IOP_OBJS) 93 | $(IOP_CC) $(IOP_CFLAGS) -o $(IOP_BIN) $(IOP_OBJS) $(IOP_LDFLAGS) $(IOP_LIBS) 94 | 95 | $(IOP_LIB) : $(IOP_OBJS) 96 | $(IOP_AR) cru $(IOP_LIB) $(IOP_OBJS) 97 | -------------------------------------------------------------------------------- /docs/FileBrowser sort+display modes.txt: -------------------------------------------------------------------------------- 1 | uLE now has 3 different display modes, as follows: 2 | 3 | Display mode 0 == Filenames only 4 | The full screen width is used to display the file/folder names, thus allowing quite long names to be fully displayed, but at cost of not being able to show other file info. This is identical to the traditional filename display mode of older uLE versions. 5 | 6 | Display mode 1 == Filenames and Info 7 | This new mode uses a little more than half the screen width to display file/folder names, and uses the remainder at the right screen edge to display file sizes and timestamps. This is done at cost of not being able to display long filenames, but since normal PS2 filenames are quite short (max 32 characters on MC), this is not a major problem, so this mode is the new default for the FileBrowser. 8 | 9 | Display mode 2 == Game Titles and Info 10 | This new mode is similar to mode 1 in how it uses the screen, except that it displays gamesave titles instead of filenames (when titles are available). Since such titles are always limited to max 32 characters there will be no space conflict (except possibly for files that don't have any titles). Gamesave titles will be displayed correctly for PS1 gamesave files, PS2 gamesave folders, and PSU gamesave backup files, and regardless of the media any of these are stored on. 11 | 12 | 13 | uLE now has 4 different sorting modes for the FileBrowser, as follows: 14 | 15 | Sort mode 0 == No sort 16 | As the name indicates, uLE does not change the display order at all for this mode, so that all objects are displayed in the order they were given by the device drivers, which presumably matches the physical order of storage. 17 | 18 | 19 | Sort mode 1 == Sort by Filename 20 | This is the default mode, and works as the traditional main sort mode of older uLE versions. Note that this also performs two other sorting tasks, as folders are displayed above files, and ELF files are displayed above all other files. Thus there may be three groups of objects in such a display. 21 | 22 | 1a: All folders, sorted by name 23 | 1b: All ELF files, sorted by name 24 | 1c: All non-ELF files, sorted by name 25 | 26 | 27 | Sort mode 2 == Sort by Game Title 28 | This works as the alternate sort mode used by older uLE versions when displaying game titles, but in the new version it can also be used when displaying filenames. In addition to the title sorting, this mode also separates folders and ELFs in the same way as mode 1. Additionally, objects that have no title will be separated to follow those of the same object type that do have titles, and the internal sorting of title-less objects will be by name. This means that such a display can contain five object groups. 29 | 30 | 2a: All folders with valid titles, sorted by title 31 | 2b: All folders lacking titles, sorted by name 32 | 2c: All ELF files, sorted by name 33 | 2d: All files with valid titles (PSU files or PS1 saves), sorted by title 34 | 2e: All non-ELF files lacking titles, sorted by name 35 | 36 | 37 | Sort mode 3 == Sort by Timestamp 38 | This new mode sorts objects by the modification timestamp, if the current device allows valid timestamps. Otherwise sorting defaults to mode 1 or 2, depending on the displayed file identifiers (file names or game titles). In all three cases this mode also performs the same separation of folders and ELFs as modes 1 and 2. When timestamps are valid such a display can contain three object groups. 39 | 40 | 3a: All folders, sorted by timestamp 41 | 3b: All ELF files, sorted by timestamp 42 | 3c: All non-ELF files, sorted by timestamp 43 | 44 | The timestamp sorting is made in 'falling' sequence, so that the most recently modified objects are displayed at the top of the list, and the oldest at its bottom. 45 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: false 6 | AlignConsecutiveBitFields: AcrossEmptyLinesAndComments 7 | AlignConsecutiveDeclarations: false 8 | AlignConsecutiveMacros: AcrossComments 9 | AlignEscapedNewlines: Left 10 | AlignOperands: Align 11 | AlignTrailingComments: true 12 | AllowAllArgumentsOnNextLine: false 13 | AllowAllConstructorInitializersOnNextLine: true 14 | AllowAllParametersOfDeclarationOnNextLine: true 15 | AllowShortBlocksOnASingleLine: Empty 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortEnumsOnASingleLine: true 18 | AllowShortFunctionsOnASingleLine: All 19 | AllowShortIfStatementsOnASingleLine: Never 20 | AllowShortLambdasOnASingleLine: Empty 21 | AllowShortLoopsOnASingleLine: false 22 | AlwaysBreakAfterReturnType: None 23 | AlwaysBreakBeforeMultilineStrings: false 24 | AlwaysBreakTemplateDeclarations: true 25 | BinPackArguments: true 26 | BinPackParameters: true 27 | BitFieldColonSpacing: Both 28 | BreakBeforeBraces: Custom 29 | BraceWrapping: 30 | AfterCaseLabel: false 31 | AfterClass: true 32 | AfterControlStatement: false 33 | AfterEnum: false 34 | AfterFunction: true 35 | AfterNamespace: true 36 | AfterObjCDeclaration: false 37 | AfterStruct: true 38 | AfterUnion: true 39 | AfterExternBlock: false 40 | BeforeCatch: false 41 | BeforeElse: false 42 | BeforeLambdaBody: false 43 | BeforeWhile: false 44 | IndentBraces: false 45 | SplitEmptyFunction: true 46 | SplitEmptyRecord: true 47 | SplitEmptyNamespace: true 48 | BreakBeforeBinaryOperators: None 49 | BreakBeforeConceptDeclarations: true 50 | BreakBeforeTernaryOperators: false 51 | BreakConstructorInitializers: BeforeComma 52 | BreakStringLiterals: true 53 | ColumnLimit: 0 54 | CommentPragmas: "^ (IWYU pragma:|NOLINT)" 55 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 56 | ConstructorInitializerIndentWidth: 4 57 | ContinuationIndentWidth: 4 58 | Cpp11BracedListStyle: true 59 | DeriveLineEnding: true 60 | DerivePointerAlignment: false 61 | DisableFormat: false 62 | EmptyLineBeforeAccessModifier: LogicalBlock 63 | FixNamespaceComments: true 64 | ForEachMacros: [] 65 | IncludeBlocks: Preserve 66 | IndentExternBlock: NoIndent 67 | IndentCaseBlocks: false 68 | IndentCaseLabels: true 69 | IndentGotoLabels: true 70 | IndentWidth: 4 71 | IndentWrappedFunctionNames: false 72 | KeepEmptyLinesAtTheStartOfBlocks: true 73 | MacroBlockBegin: "" 74 | MacroBlockEnd: "" 75 | MaxEmptyLinesToKeep: 3 76 | NamespaceIndentation: None 77 | ObjCBlockIndentWidth: 2 78 | ObjCSpaceAfterProperty: false 79 | ObjCSpaceBeforeProtocolList: true 80 | PenaltyBreakAssignment: 80 81 | PenaltyBreakBeforeFirstCallParameter: 19 82 | PenaltyBreakComment: 300 83 | PenaltyBreakFirstLessLess: 120 84 | PenaltyBreakString: 1000 85 | PenaltyBreakTemplateDeclaration: 80 86 | PenaltyExcessCharacter: 1000000 87 | PenaltyIndentedWhitespace: 80 88 | PenaltyReturnTypeOnItsOwnLine: 60 89 | PointerAlignment: Right 90 | # uncomment below when clang >=13 will be out 91 | # IndentPPDirectives: AfterHash 92 | # PPIndentWidth: 1 93 | ReflowComments: true 94 | SortIncludes: false 95 | SpaceAfterCStyleCast: false 96 | SpaceAfterLogicalNot: false 97 | SpaceAroundPointerQualifiers: Default 98 | SpaceBeforeAssignmentOperators: true 99 | SpaceBeforeCaseColon: false 100 | SpaceBeforeCpp11BracedList: true 101 | SpaceBeforeInheritanceColon: false 102 | SpaceBeforeParens: ControlStatements 103 | SpaceBeforeRangeBasedForLoopColon: true 104 | SpaceBeforeSquareBrackets: false 105 | SpaceInEmptyBlock: false 106 | SpaceInEmptyParentheses: false 107 | SpacesBeforeTrailingComments: 2 108 | SpacesInAngles: false 109 | SpacesInConditionalStatement: false 110 | SpacesInContainerLiterals: true 111 | SpacesInCStyleCastParentheses: false 112 | SpacesInParentheses: false 113 | SpacesInSquareBrackets: false 114 | Standard: Cpp11 115 | TabWidth: 4 116 | UseTab: Never 117 | -------------------------------------------------------------------------------- /vmc_fs/vmc_fs.c: -------------------------------------------------------------------------------- 1 | #include "vmc.h" 2 | 3 | 4 | // Driver fonctions 5 | 6 | #define MODNAME "vmc_fs" 7 | IRX_ID(MODNAME, 1, 2); 8 | 9 | 10 | // Static variables. 11 | static iop_device_t s_Vmc_Driver; 12 | static iop_device_ops_t s_Vmc_Functions; 13 | 14 | // Global variables. 15 | struct global_vmc g_Vmc_Image[2]; 16 | int g_Vmc_Remove_Flag; 17 | int g_Vmc_Initialized; 18 | 19 | //---------------------------------------------------------------------------- 20 | // Initialize vmc driver 21 | //---------------------------------------------------------------------------- 22 | int Vmc_Initialize(iop_device_t *driver) 23 | { 24 | 25 | if (g_Vmc_Initialized) 26 | return VMCFS_ERR_NO; 27 | 28 | g_Vmc_Initialized = TRUE; 29 | 30 | // init the global file descriptor to something negative ( ubergeek like 42, and polo like 35 so - 4235 ) 31 | g_Vmc_Image[0].fd = -4235; 32 | g_Vmc_Image[1].fd = -4235; 33 | 34 | DEBUGPRINT(1, "vmc_fs: Filesystem Driver Initialized\n"); 35 | 36 | return VMCFS_ERR_NO; 37 | } 38 | 39 | 40 | //---------------------------------------------------------------------------- 41 | // Deinitialize vmc driver 42 | //---------------------------------------------------------------------------- 43 | int Vmc_Deinitialize(iop_device_t *driver) 44 | { 45 | 46 | int i = 0; 47 | 48 | if (!g_Vmc_Initialized) 49 | return VMCFS_ERR_INITIALIZED; 50 | 51 | g_Vmc_Initialized = FALSE; 52 | 53 | for (i = 0; i < 2; i++) { 54 | 55 | if (g_Vmc_Image[i].fd >= 0) { 56 | 57 | close(g_Vmc_Image[i].fd); 58 | } 59 | } 60 | 61 | DEBUGPRINT(1, "vmc_fs: Filesystem Driver Deinitialized\n"); 62 | 63 | return VMCFS_ERR_NO; 64 | } 65 | 66 | // Entry point of the driver. 67 | int _start(int argc, char **argv) 68 | { 69 | 70 | printf("vmc_fs: Created by ubergeek42\n"); 71 | printf("vmc_fs: ... Improved by Polo35.\n"); 72 | printf("vmc_fs: Version 1.2\n"); 73 | 74 | g_Vmc_Initialized = FALSE; 75 | g_Vmc_Remove_Flag = FALSE; 76 | 77 | s_Vmc_Driver.type = (IOP_DT_FS | IOP_DT_FSEXT); 78 | s_Vmc_Driver.version = 1; 79 | s_Vmc_Driver.name = "vmc"; // the name used to access this device ( eg: vmc0: / ) 80 | s_Vmc_Driver.desc = "Virtual Memory Card s_Vmc_Driver"; 81 | s_Vmc_Driver.ops = &s_Vmc_Functions; 82 | 83 | // Typecasting to ( void* ) eliminates a bunch of warnings. 84 | s_Vmc_Functions.init = Vmc_Initialize; 85 | s_Vmc_Functions.deinit = Vmc_Deinitialize; 86 | s_Vmc_Functions.format = Vmc_Format; 87 | s_Vmc_Functions.open = Vmc_Open; 88 | s_Vmc_Functions.close = Vmc_Close; 89 | s_Vmc_Functions.read = Vmc_Read; 90 | s_Vmc_Functions.write = Vmc_Write; 91 | s_Vmc_Functions.lseek = Vmc_Lseek; 92 | s_Vmc_Functions.ioctl = Vmc_Ioctl; 93 | s_Vmc_Functions.remove = Vmc_Remove; 94 | s_Vmc_Functions.mkdir = Vmc_Mkdir; 95 | s_Vmc_Functions.rmdir = Vmc_Rmdir; 96 | s_Vmc_Functions.dopen = Vmc_Dopen; 97 | s_Vmc_Functions.dclose = Vmc_Dclose; 98 | s_Vmc_Functions.dread = Vmc_Dread; 99 | s_Vmc_Functions.getstat = Vmc_Getstat; 100 | s_Vmc_Functions.chstat = Vmc_Chstat; 101 | /* Extended ops start here. */ 102 | s_Vmc_Functions.rename = Vmc_Rename; 103 | s_Vmc_Functions.chdir = Vmc_Chdir; 104 | s_Vmc_Functions.sync = Vmc_Sync; 105 | s_Vmc_Functions.mount = Vmc_Mount; 106 | s_Vmc_Functions.umount = Vmc_Umount; 107 | s_Vmc_Functions.lseek64 = Vmc_Lseek64; 108 | s_Vmc_Functions.devctl = Vmc_Devctl; 109 | s_Vmc_Functions.symlink = Vmc_Symlink; 110 | s_Vmc_Functions.readlink = Vmc_Readlink; 111 | s_Vmc_Functions.ioctl2 = Vmc_Ioctl2; 112 | 113 | 114 | // Add the Driver using the ioman export 115 | DelDrv(s_Vmc_Driver.name); 116 | AddDrv(&s_Vmc_Driver); 117 | 118 | // And we are done! 119 | DEBUGPRINT(1, "vmc_fs: Filesystem Driver %s added!\n", s_Vmc_Driver.name); 120 | 121 | return 0; 122 | } 123 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #.SILENT: 2 | 3 | EE_BIN = BOOT-UNC.ELF 4 | EE_BIN_PKD = BOOT.ELF 5 | EE_OBJS = main.o nfs.o smb2.o pad.o config.o elf.o draw.o loader_elf.o filer.o \ 6 | poweroff_irx.o iomanx_irx.o filexio_irx.o ps2atad_irx.o DEV9_irx.o NETMAN_irx.o \ 7 | SMAP_irx.o ps2hdd_irx.o ps2fs_irx.o usbd_irx.o usbhdfsd_irx.o mcman_irx.o mcserv_irx.o\ 8 | cdfs_irx.o vmc_fs_irx.o ps2kbd_irx.o\ 9 | hdd.o hdl_rpc.o hdl_info_irx.o editor.o timer.o jpgviewer.o icon.o lang.o\ 10 | font_uLE.o makeicon.o chkesr.o sior_irx.o allowdvdv_irx.o 11 | EE_INCS := -I$(PS2DEV)/gsKit/include -I$(PS2SDK)/ports/include 12 | 13 | EE_LDFLAGS := -L$(PS2DEV)/gsKit/lib -L$(PS2SDK)/ports/lib -s 14 | EE_LIBS = -lnfs -lsmb2 -lps2ip -lnetman -ldebug \ 15 | -lgskit -ldmakit -ljpeg_ps2_addons -ljpeg -lpad -lmc -lhdd -lkbd -lm \ 16 | -lcdvd -lfileXio -lpatches -lpoweroff -ldebug -lsior 17 | EE_CFLAGS := -mno-gpopt -G0 18 | 19 | BIN2S = $(PS2SDK)/bin/bin2s 20 | 21 | .PHONY: all run reset clean rebuild format format-check 22 | 23 | all: githash.h $(EE_BIN_PKD) 24 | 25 | $(EE_BIN_PKD): $(EE_BIN) 26 | ps2-packer $< $@ 27 | 28 | reset: clean 29 | ps2client -h 192.168.0.10 reset 30 | 31 | format: 32 | find . -type f -a \( -iname \*.h -o -iname \*.c \) | xargs clang-format -i 33 | 34 | format-check: 35 | @! find . -type f -a \( -iname \*.h -o -iname \*.c \) | xargs clang-format -style=file -output-replacements-xml | grep "/dev/null 36 | 37 | githash.h: 38 | printf '#ifndef ULE_VERDATE\n#define ULE_VERDATE "' > $@ && \ 39 | git show -s --format=%cd --date=local | tr -d "\n" >> $@ && \ 40 | printf '"\n#endif\n' >> $@ 41 | printf '#ifndef GIT_HASH\n#define GIT_HASH "' >> $@ && \ 42 | git rev-parse --short HEAD | tr -d "\n" >> $@ && \ 43 | printf '"\n#endif\n' >> $@ 44 | 45 | DEV9_irx.c: $(PS2SDK)/iop/irx/ps2dev9.irx 46 | bin2c $< DEV9_irx.c DEV9_irx 47 | 48 | NETMAN_irx.c: $(PS2SDK)/iop/irx/netman.irx 49 | bin2c $< NETMAN_irx.c NETMAN_irx 50 | 51 | SMAP_irx.c: $(PS2SDK)/iop/irx/smap.irx 52 | bin2c $< SMAP_irx.c SMAP_irx 53 | 54 | mcman_irx.s: $(PS2SDK)/iop/irx/mcman.irx 55 | $(BIN2S) $< $@ mcman_irx 56 | 57 | mcserv_irx.s: $(PS2SDK)/iop/irx/mcserv.irx 58 | $(BIN2S) $< $@ mcserv_irx 59 | 60 | usbd_irx.s: $(PS2SDK)/iop/irx/usbd.irx 61 | $(BIN2S) $< $@ usbd_irx 62 | 63 | usbhdfsd_irx.s: $(PS2SDK)/iop/irx/usbhdfsd.irx 64 | $(BIN2S) $< $@ usb_mass_irx 65 | 66 | cdfs_irx.s: $(PS2SDK)/iop/irx/cdfs.irx 67 | $(BIN2S) $< $@ cdfs_irx 68 | 69 | poweroff_irx.s: $(PS2SDK)/iop/irx/poweroff.irx 70 | $(BIN2S) $< $@ poweroff_irx 71 | 72 | iomanx_irx.s: $(PS2SDK)/iop/irx/iomanX.irx 73 | $(BIN2S) $< $@ iomanx_irx 74 | 75 | filexio_irx.s: $(PS2SDK)/iop/irx/fileXio.irx 76 | $(BIN2S) $< $@ filexio_irx 77 | 78 | ps2atad_irx.s: $(PS2SDK)/iop/irx/ps2atad.irx 79 | $(BIN2S) $< $@ ps2atad_irx 80 | 81 | ps2hdd_irx.s: $(PS2SDK)/iop/irx/ps2hdd-xosd.irx 82 | $(BIN2S) $< $@ ps2hdd_irx 83 | 84 | ps2fs_irx.s: $(PS2SDK)/iop/irx/ps2fs-xosd.irx 85 | $(BIN2S) $< $@ ps2fs_irx 86 | 87 | hdl_info/hdl_info.irx: hdl_info 88 | $(MAKE) -C $< 89 | 90 | hdl_info_irx.s: hdl_info/hdl_info.irx 91 | $(BIN2S) $< $@ hdl_info_irx 92 | 93 | vmc_fs/vmc_fs.irx: vmc_fs 94 | $(MAKE) -C $< 95 | 96 | vmc_fs_irx.s: vmc_fs/vmc_fs.irx 97 | $(BIN2S) $< $@ vmc_fs_irx 98 | 99 | loader/loader.elf: loader 100 | $(MAKE) -C $< 101 | 102 | loader_elf.s: loader/loader.elf 103 | $(BIN2S) $< $@ loader_elf 104 | 105 | ps2kbd_irx.s: $(PS2SDK)/iop/irx/ps2kbd.irx 106 | $(BIN2S) $< $@ ps2kbd_irx 107 | 108 | sior_irx.s: $(PS2SDK)/iop/irx/sior.irx 109 | $(BIN2S) $< $@ sior_irx 110 | 111 | AllowDVDV/AllowDVDV.irx: AllowDVDV 112 | $(MAKE) -C $< 113 | 114 | allowdvdv_irx.s: AllowDVDV/AllowDVDV.irx 115 | $(BIN2S) $< $@ allowdvdv_irx 116 | 117 | clean: 118 | $(MAKE) -C hdl_info clean 119 | $(MAKE) -C loader clean 120 | $(MAKE) -C vmc_fs clean 121 | $(MAKE) -C AllowDVDV clean 122 | rm -f githash.h *.s $(EE_OBJS) $(EE_BIN) $(EE_BIN_PKD) 123 | 124 | rebuild: clean all 125 | 126 | include $(PS2SDK)/samples/Makefile.pref 127 | include $(PS2SDK)/samples/Makefile.eeglobal 128 | -------------------------------------------------------------------------------- /docs/New resolutions.txt: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | Filename: New Resolutions.txt 3 | ----------------------------------------------------------------------------- 4 | LaunchELF is now relying on gsKit to initialize the screen display parameters, rather than setting them directly. 5 | As such, the Screen_X and Screen_Y have been deprecated, in favour of Screen_Offset_X and Screen_Offset_Y. 6 | Unlike their predecessors, Screen_Offset_X and Screen_Offset_Y are relative to the display mode's X/Y offsets. 7 | They are also limited to this range: 8 | -StartX <= Screen_Offset_X <= StartX 9 | -StartY <= Screen_Offset_Y <= StartY 10 | Where StartX and StartY are the display mode offsets determined by gsKit. 11 | 12 | The Interlace option was deprecated, in favour of a true progressive mode. 13 | The Interlace option depended on a custom gsKit version, which halved the vertical height of the screen at the library level. 14 | Deprecating this option has allowed LaunchELF to use a vanilla copy of gsKit. 15 | 16 | ----------------------------------------------------------------------------- 17 | The text below relates to an older version update, and is no longer valid. 18 | ----------------------------------------------------------------------------- 19 | From version v3.81 and on uLaunchELF is using gsKit instead of libito to handle screen display, which has resulted in yet another increase of the screen resolution. As a result of this the old settings for screen offsets have yet again become invalid, but this time we have added a filter to the configuration loader, so that it can and will adapt old offset settings, when it recognizes that the configuration file was saved by an older version of the program. (When the CNF_version value in the file is less than 3.) 20 | 21 | Another big change in this version is that interlace mode is now the default, and even mandatory, so non-interlaced modes can no longer be set. (Would halve resolution...) 22 | 23 | In case you wish to edit the offsets yourself, the new defaults are as follows: 24 | 25 | NTSC with Interlace ON: 26 | Screen_X = 632 27 | Screen_Y = 50 28 | 29 | PAL with Interlace ON: 30 | Screen_X = 652 31 | Screen_Y = 72 32 | 33 | From version 3.84 the gsKit versions also support non-interlaced modes, and 34 | while these are not default, you may still find it useful to know that they 35 | use the following offsets to cover the same screen area (almost) as achieved 36 | in interlace modes using the settings that were described above: 37 | 38 | NTSC with Interlace OFF: 39 | Screen_X = 632 40 | Screen_Y = 26 41 | 42 | PAL with Interlace OFF: 43 | Screen_X = 652 44 | Screen_Y = 37 45 | 46 | ----------------------------------------------------------------------------- 47 | The text below relates to an older version update, and is no longer valid. 48 | ----------------------------------------------------------------------------- 49 | From version v3.58 and on uLaunchELF uses screen display routines that have been heavily modified compared to all previous versions, and now use a much higher resolution than any of them. Because of this the old defaults for screen offsets are no longer valid, and will need to be changed if you want to keep using CNF files from those old versions. Just transfer them to your PC, and edit the values of Screen_X and Screen_Y to the new defaults, as follows: 50 | 51 | NTSC with Interlace OFF: 52 | Screen_X = 158 53 | Screen_Y = 26 54 | 55 | NTSC with Interlace ON: 56 | Screen_X = 158 57 | Screen_Y = 50 58 | 59 | PAL with Interlace OFF: 60 | Screen_X = 163 61 | Screen_Y = 37 62 | 63 | PAL with Interlace ON: 64 | Screen_X = 163 65 | Screen_Y = 72 66 | 67 | If you don't want to bother with editing the CNFs you can also choose to erase them, as the new defaults will be used automatically if no CNF is found on startup. 68 | NB: That feature didn't work correctly in v3.58, but it does in all later versions. 69 | 70 | Best regards: Ronald Andersson (AKA: dlanor) 71 | ----------------------------------------------------------------------------- 72 | End of file: New Resolutions.txt 73 | ----------------------------------------------------------------------------- 74 | -------------------------------------------------------------------------------- /docs/Multiple USB_mass drives and partitions.txt: -------------------------------------------------------------------------------- 1 | New "mass:" capabilities of uLE : 2 | --------------------------------- 3 | 4 | In uLE v4.32 a new revision of the usbhdfsd driver is used, as improved by 'radad' to support multiple USB storage drives and partitions, and the uLE FileBrowser has likewise been improved by me ('dlanor') to support this. The current implementation will allow up to 5 simultaneously connected USB drives to be accessed, though you will need a USB hub to be able to connect so many, since the PS2 itself only has two USB ports. Each drive may also have more than one partition, each of which will then appear as an independent "mass?:" drive in uLE, with the maximum number of such logical drives being 10. Note however that fully incompatible partitions do not count here, such as NTFS drives. Such partitions will just be ignored by uLE. 5 | 6 | As before, uLE does not load USB_mass drivers until the user attempts to access mass:, and it is only when the user browses to the basic "mass:" device that the new features are enabled. Until then only that one "mass:" drive will be visible in the root device list of the FileBrowser. 7 | 8 | But once you have browsed to mass: uLE will scan the ports for USB drives, and will present these in the root device list the next time you browse there. The same also applies to devices added or removed by 'hotplugging' during a browser session, as the changes will then be displayed the next time you browse to the root device list. (If already there, press 'Triangle' to refresh the list.) But there is one limitation, as the scan for changes will be skipped if less than 5 seconds have passed since the previous scan. 9 | 10 | The maximum list of USB_mass drives currently looks like this: 11 | 12 | mass: 13 | mass1: 14 | mass2: 15 | mass3: 16 | mass4: 17 | mass5: 18 | mass6: 19 | mass7: 20 | mass8: 21 | mass9: 22 | 23 | 24 | Backwards compatibility with old applications' use of "mass:" : 25 | --------------------------------------------------------------- 26 | 27 | When uLE is launched with a given drive set the assignation of logical drive numbers is made in such a fashion that "mass:" will be the same drive seen as "mass:" by most older applications, capable of accessing only one USB drive. This is to allow simple cooperative use of one drive between uLE and such applications. But if you hotplug drives after launching uLE, then this relationship will not necessarily hold true. For such cases you should relaunch uLE, to test which the 'real' "mass:" drive is, that old applications may access. This is important, for example, when you intend one of the drives to also be used by USBAdvance/USBExtreme, or by various emulators. 28 | 29 | Another thing to remember here is that current implementations of SMS, the media player, do not support more than one partition per USB drive, though it does allow multiple drives. So when using uLE to prepare media files for SMS on a USB drive, you should always use only the first partition. This applies mainly when using the internal drivers of SMS. If you use old external drivers with SMS, then it works just like other old applications. 30 | 31 | 32 | Additional considerations related to new "mass:" capabilities : 33 | --------------------------------------------------------------- 34 | 35 | It is also permitted to use the form "mass0:" to access the "mass:" drive, but for compatibility reasons the "mass0:" form will not be displayed as such in the browser. 36 | 37 | One more important thing to realize is that hotplugging may leave 'holes' in the drive list, as the remaining drives will keep their old drive numbers when one or more other drives are removed. So if you started with a 4-drive setup and then remove the first and the third drives (mass: and mass2:), then the root device list will only show the following USB_mass drives: 38 | 39 | mass1: 40 | mass3: 41 | 42 | And if you then reinsert the drive that previously was mass2: into any free USB port and refresh the device list, that drive will then be shown as "mass:"... 43 | 44 | Even more confusingly: If you instead insert a drive having three partitions, then these will be designated as "mass:", "mass2:" and "mass4:" for the case above, as "mass1:" and "mass3:" are already used for other drives... 45 | 46 | This new FileBrowser capability may take some getting used to, and for safest usage I recommend having some file or folder in the root directory of each USB partition, that uniquely identifies both that particular drive and that particular partition. Otherwise you may mistake one drive for the other, with disastrous consequences when making a backup for example (restoring old stuff when you wanted to backup new stuff, or vice versa). So take care. 47 | 48 | And since this is a brand new feature based on a brand new driver revision, be aware that this stuff has not yet been as rigorously tested as the old drivers. So be careful, and try to always have a backup of the files you work with. 49 | 50 | Best regards: dlanor 51 | -------------------------------------------------------------------------------- /loader/loader.c: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------- 2 | //File name: loader.c 3 | //-------------------------------------------------------------- 4 | //dlanor: This subprogram has been modified to minimize the code 5 | //dlanor: size of the resident loader portion. Some of the parts 6 | //dlanor: that were moved into the main program include loading 7 | //dlanor: of all IRXs and mounting pfs0: for ELFs on hdd. 8 | //dlanor: Another change was to skip threading in favor of ExecPS2 9 | /*================================================================== 10 | == == 11 | == Copyright(c)2004 Adam Metcalf(gamblore_@hotmail.com) == 12 | == Copyright(c)2004 Thomas Hawcroft(t0mb0la@yahoo.com) == 13 | == This file is subject to terms and conditions shown in the == 14 | == file LICENSE which should be kept in the top folder of == 15 | == this distribution. == 16 | == == 17 | == Portions of this code taken from PS2Link: == 18 | == pkoLoadElf == 19 | == wipeUserMemory == 20 | == (C) 2003 Tord Lindstrom (pukko@home.se) == 21 | == (C) 2003 adresd (adresd_ps2dev@yahoo.com) == 22 | == Portions of this code taken from Independence MC exploit == 23 | == tLoadElf == 24 | == LoadAndRunHDDElf == 25 | == (C) 2003 Marcus Brown == 26 | == == 27 | ==================================================================*/ 28 | #include "tamtypes.h" 29 | #include "debug.h" 30 | #include "kernel.h" 31 | #include "iopcontrol.h" 32 | #include "sifrpc.h" 33 | #include "loadfile.h" 34 | #include "string.h" 35 | #include "iopheap.h" 36 | #include "errno.h" 37 | //-------------------------------------------------------------- 38 | 39 | //-------------------------------------------------------------- 40 | // Redefinition of init/deinit libc: 41 | //-------------------------------------------------------------- 42 | // DON'T REMOVE is for reducing binary size. 43 | // These funtios are defined as weak in /libc/src/init.c 44 | //-------------------------------------------------------------- 45 | void _ps2sdk_libc_init() {} 46 | void _ps2sdk_libc_deinit() {} 47 | 48 | //-------------------------------------------------------------- 49 | //End of data declarations 50 | //-------------------------------------------------------------- 51 | //Start of function code: 52 | //-------------------------------------------------------------- 53 | // Clear user memory 54 | // PS2Link (C) 2003 Tord Lindstrom (pukko@home.se) 55 | // (C) 2003 adresd (adresd_ps2dev@yahoo.com) 56 | //-------------------------------------------------------------- 57 | static void wipeUserMem(void) 58 | { 59 | int i; 60 | for (i = 0x100000; i < GetMemorySize(); i += 64) { 61 | asm volatile( 62 | "\tsq $0, 0(%0) \n" 63 | "\tsq $0, 16(%0) \n" 64 | "\tsq $0, 32(%0) \n" 65 | "\tsq $0, 48(%0) \n" ::"r"(i)); 66 | } 67 | } 68 | 69 | //-------------------------------------------------------------- 70 | //End of func: void wipeUserMem(void) 71 | //-------------------------------------------------------------- 72 | // *** MAIN *** 73 | //-------------------------------------------------------------- 74 | int main(int argc, char *argv[]) 75 | { 76 | static t_ExecData elfdata; 77 | char *target, *path; 78 | char *args[1]; 79 | int ret; 80 | 81 | // Initialize 82 | SifInitRpc(0); 83 | wipeUserMem(); 84 | 85 | if (argc != 2) { // arg1=path to ELF, arg2=partition to mount 86 | SifExitRpc(); 87 | return -EINVAL; 88 | } 89 | 90 | target = argv[0]; 91 | path = argv[1]; 92 | 93 | //Writeback data cache before loading ELF. 94 | FlushCache(0); 95 | ret = SifLoadElf(target, &elfdata); 96 | if (ret == 0) { 97 | args[0] = path; 98 | 99 | if (strncmp(path, "hdd", 3) == 0 && (path[3] >= '0' && path[3] <= ':')) { /* Final IOP reset, to fill the IOP with the default modules. 100 | It appears that it was once a thing for the booting software to leave the IOP with the required IOP modules. 101 | This can be seen in OSDSYS v1.0x (no IOP reboot) and the mechanism to boot DVD player updates (OSDSYS will get LoadExecPS2 to load SIO2 modules). 102 | However, it changed with the introduction of the HDD unit, as the software booted may be built with a different SDK revision. 103 | 104 | Reboot the IOP, to leave it in a clean & consistent state. 105 | But do not do that for boot targets on other devices, for backward-compatibility with older (homebrew) software. */ 106 | while (!SifIopReset("", 0)) { 107 | }; 108 | while (!SifIopSync()) { 109 | }; 110 | } 111 | 112 | SifExitRpc(); 113 | 114 | FlushCache(0); 115 | FlushCache(2); 116 | 117 | ExecPS2((void *)elfdata.epc, (void *)elfdata.gp, 1, args); 118 | return 0; 119 | } else { 120 | SifExitRpc(); 121 | return -ENOENT; 122 | } 123 | } 124 | //-------------------------------------------------------------- 125 | //End of func: int main(int argc, char *argv[]) 126 | //-------------------------------------------------------------- 127 | //End of file: loader.c 128 | //-------------------------------------------------------------- 129 | -------------------------------------------------------------------------------- /vmc_fs/vmc_fat.c: -------------------------------------------------------------------------------- 1 | #include "vmc.h" 2 | 3 | 4 | // Fat table functions 5 | 6 | unsigned int getFatEntry(int fd, unsigned int cluster, unsigned int *indir_fat_clusters, GetFat_Mode Mode) 7 | { 8 | 9 | int unit = (fd == g_Vmc_Image[0].fd) ? 0 : 1; 10 | 11 | // The fat index, aka which cluster we want to know about 12 | unsigned int fat_index = cluster; 13 | 14 | // The offset in the fat cluster where we can find information about the sector 15 | unsigned int fat_offset = fat_index % (g_Vmc_Image[unit].cluster_size / 4); 16 | 17 | // Which fat cluster that the information would be in 18 | unsigned int indirect_index = fat_index / (g_Vmc_Image[unit].cluster_size / 4); 19 | 20 | // The offset in the indirect fat cluster that points to the fat table we are interested in 21 | unsigned int indirect_offset = indirect_index % (g_Vmc_Image[unit].cluster_size / 4); 22 | 23 | // This gives the location of the fat_offset inside of the indirect fat cluster list. Each indirect fat cluster can point to 24 | // 256 regular fat clusters, and each fat cluster holds information on 256 sectors. 25 | unsigned int dbl_indirect_index = fat_index / ((g_Vmc_Image[unit].cluster_size / 4) * (g_Vmc_Image[unit].cluster_size / 4)); 26 | 27 | // Cache indirect file table? ( Generally we will be accessing the first part of it for most virtual memory cards ) 28 | // Get the data for the indirect fat cluster ( as indicated by dbl_indirect_index ) 29 | unsigned int indirect_cluster_num = indir_fat_clusters[dbl_indirect_index]; 30 | 31 | if (g_Vmc_Image[unit].last_idc != indirect_cluster_num) 32 | readCluster(fd, (unsigned char *)g_Vmc_Image[unit].indirect_cluster, indirect_cluster_num); 33 | 34 | g_Vmc_Image[unit].last_idc = indirect_cluster_num; 35 | 36 | // Get the data from the fat cluster ( pointed to by the indirect fat cluster ) 37 | unsigned int fat_cluster_num = g_Vmc_Image[unit].indirect_cluster[indirect_offset]; 38 | 39 | if (g_Vmc_Image[unit].last_cluster != fat_cluster_num) 40 | readCluster(fd, (unsigned char *)g_Vmc_Image[unit].fat_cluster, fat_cluster_num); 41 | 42 | g_Vmc_Image[unit].last_cluster = fat_cluster_num; 43 | 44 | // Check if the entry in the fat table corresponds to a free cluster or a eof cluster 45 | if (g_Vmc_Image[unit].fat_cluster[fat_offset] == FREE_CLUSTER || g_Vmc_Image[unit].fat_cluster[fat_offset] == EOF_CLUSTER) 46 | return g_Vmc_Image[unit].fat_cluster[fat_offset]; 47 | 48 | if (Mode == FAT_MASK) { 49 | 50 | if (g_Vmc_Image[unit].fat_cluster[fat_offset] & MASK_CLUSTER) { 51 | 52 | return MASK_CLUSTER; 53 | 54 | } else { 55 | 56 | return 0; 57 | } 58 | } 59 | 60 | // Return the fat entry, but remove the most significant bit. 61 | return g_Vmc_Image[unit].fat_cluster[fat_offset] & FREE_CLUSTER; 62 | } 63 | 64 | unsigned int setFatEntry(int fd, unsigned int cluster, unsigned int value, unsigned int *indir_fat_clusters, SetFat_Mode Mode) 65 | { 66 | 67 | int unit = (fd == g_Vmc_Image[0].fd) ? 0 : 1; 68 | 69 | // The fat index, aka which cluster we want to know about 70 | unsigned int fat_index = cluster; 71 | 72 | // The offset in the fat cluster where we can find information about the sector 73 | unsigned int fat_offset = fat_index % (g_Vmc_Image[unit].cluster_size / 4); 74 | 75 | // Which fat cluster that the information would be in 76 | unsigned int indirect_index = fat_index / (g_Vmc_Image[unit].cluster_size / 4); 77 | 78 | // The offset in the indirect fat cluster that points to the fat table we are interested in 79 | unsigned int indirect_offset = indirect_index % (g_Vmc_Image[unit].cluster_size / 4); 80 | 81 | // This gives the location of the fat_offset inside of the indirect fat cluster list. Each indirect fat cluster can point to 82 | // 256 regular fat clusters, and each fat cluster holds information on 256 sectors. 83 | unsigned int dbl_indirect_index = fat_index / ((g_Vmc_Image[unit].cluster_size / 4) * (g_Vmc_Image[unit].cluster_size / 4)); 84 | 85 | // Cache indirect file table? ( Generally we will be accessing the first part of it for most virtual memory cards 86 | // Get the data for the indirect fat cluster ( as indicated by dbl_indirect_index ) 87 | unsigned int indirect_cluster_num = indir_fat_clusters[dbl_indirect_index]; 88 | 89 | if (g_Vmc_Image[unit].last_idc != indirect_cluster_num) 90 | readCluster(fd, (unsigned char *)g_Vmc_Image[unit].indirect_cluster, indirect_cluster_num); 91 | 92 | g_Vmc_Image[unit].last_idc = indirect_cluster_num; 93 | 94 | // Get the data from the fat cluster ( pointed to by the indirect fat cluster ) 95 | unsigned int fat_cluster_num = g_Vmc_Image[unit].indirect_cluster[indirect_offset]; 96 | 97 | if (g_Vmc_Image[unit].last_cluster != fat_cluster_num) 98 | readCluster(fd, (unsigned char *)g_Vmc_Image[unit].fat_cluster, fat_cluster_num); 99 | 100 | g_Vmc_Image[unit].last_cluster = fat_cluster_num; 101 | 102 | if (value == FREE_CLUSTER || value == EOF_CLUSTER || Mode == FAT_RESET) { 103 | 104 | g_Vmc_Image[unit].fat_cluster[fat_offset] = value; 105 | 106 | } else { 107 | 108 | g_Vmc_Image[unit].fat_cluster[fat_offset] = value | MASK_CLUSTER; 109 | } 110 | 111 | writeCluster(fd, (unsigned char *)g_Vmc_Image[unit].fat_cluster, fat_cluster_num); 112 | 113 | // Update last free cluster 114 | if ((value == FREE_CLUSTER && Mode == FAT_SET) || (Mode == FAT_RESET)) { 115 | 116 | if (cluster < g_Vmc_Image[unit].last_free_cluster) { 117 | 118 | g_Vmc_Image[unit].last_free_cluster = cluster; 119 | } 120 | } 121 | 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /vmc_fs/vmc_ps2.c: -------------------------------------------------------------------------------- 1 | #include "vmc.h" 2 | 3 | 4 | // Functions specific to the ps2 5 | 6 | int readPage(int fd, u8 *page, unsigned int pagenum) 7 | { 8 | 9 | int unit; 10 | unsigned int position; 11 | 12 | unit = (fd == g_Vmc_Image[0].fd) ? 0 : 1; 13 | 14 | if (g_Vmc_Image[unit].ecc_flag) { 15 | 16 | position = pagenum * (g_Vmc_Image[unit].header.page_size + 0x10); 17 | 18 | } else { 19 | 20 | position = pagenum * g_Vmc_Image[unit].header.page_size; 21 | } 22 | 23 | lseek(fd, position, SEEK_SET); 24 | read(fd, page, g_Vmc_Image[unit].header.page_size); 25 | 26 | return 0; 27 | } 28 | 29 | int readCluster(int fd, u8 *cluster, unsigned int clusternum) 30 | { 31 | 32 | int i, unit; 33 | u8 *Page_Data; 34 | unsigned int Page_Num; 35 | 36 | unit = (fd == g_Vmc_Image[0].fd) ? 0 : 1; 37 | 38 | Page_Num = clusternum * g_Vmc_Image[unit].header.pages_per_cluster; 39 | 40 | Page_Data = (u8 *)malloc((g_Vmc_Image[unit].header.page_size + 0xFF) & ~(unsigned int)0xFF); 41 | 42 | for (i = 0; i < g_Vmc_Image[unit].header.pages_per_cluster; i++) { 43 | 44 | memset(Page_Data, g_Vmc_Image[unit].erase_byte, g_Vmc_Image[unit].header.page_size); 45 | 46 | readPage(fd, Page_Data, Page_Num + i); 47 | 48 | memcpy(cluster + (i * g_Vmc_Image[unit].header.page_size), Page_Data, g_Vmc_Image[unit].header.page_size); 49 | } 50 | 51 | free(Page_Data); 52 | 53 | return 0; 54 | } 55 | 56 | int writePage(int fd, u8 *page, unsigned int pagenum) 57 | { 58 | 59 | int unit; 60 | unsigned int position; 61 | 62 | unit = (fd == g_Vmc_Image[0].fd) ? 0 : 1; 63 | 64 | if (g_Vmc_Image[unit].ecc_flag) { 65 | 66 | position = pagenum * (g_Vmc_Image[unit].header.page_size + 0x10); 67 | 68 | } else { 69 | 70 | position = pagenum * g_Vmc_Image[unit].header.page_size; 71 | } 72 | 73 | lseek(fd, position, SEEK_SET); 74 | write(fd, page, g_Vmc_Image[unit].header.page_size); 75 | 76 | if (g_Vmc_Image[unit].ecc_flag) { 77 | 78 | u8 *ECC_Data; 79 | 80 | ECC_Data = (u8 *)malloc((0x10 + 0xFF) & ~(unsigned int)0xFF); 81 | 82 | buildECC(unit, page, ECC_Data); 83 | write(fd, ECC_Data, 0x10); 84 | 85 | free(ECC_Data); 86 | } 87 | 88 | return 0; 89 | } 90 | 91 | int writeCluster(int fd, u8 *cluster, unsigned int clusternum) 92 | { 93 | 94 | int i, unit; 95 | u8 *Page_Data; 96 | unsigned int Page_Num; 97 | 98 | unit = (fd == g_Vmc_Image[0].fd) ? 0 : 1; 99 | 100 | Page_Num = clusternum * g_Vmc_Image[unit].header.pages_per_cluster; 101 | 102 | Page_Data = (u8 *)malloc((g_Vmc_Image[unit].header.page_size + 0xFF) & ~(unsigned int)0xFF); 103 | 104 | for (i = 0; i < g_Vmc_Image[unit].header.pages_per_cluster; i++) { 105 | 106 | memset(Page_Data, g_Vmc_Image[unit].erase_byte, g_Vmc_Image[unit].header.page_size); 107 | memcpy(Page_Data, cluster + (i * g_Vmc_Image[unit].header.page_size), g_Vmc_Image[unit].header.page_size); 108 | 109 | writePage(fd, Page_Data, Page_Num + i); 110 | } 111 | 112 | free(Page_Data); 113 | 114 | return 0; 115 | } 116 | 117 | int writeClusterPart(int fd, u8 *cluster, unsigned int clusternum, int cluster_offset, int size) 118 | { 119 | 120 | int i, unit; 121 | u8 *Page_Data; 122 | unsigned int Page_Num, Page_offset; 123 | 124 | unit = (fd == g_Vmc_Image[0].fd) ? 0 : 1; 125 | 126 | Page_Num = clusternum * g_Vmc_Image[unit].header.pages_per_cluster; 127 | Page_offset = cluster_offset; 128 | 129 | Page_Data = (u8 *)malloc((g_Vmc_Image[unit].header.page_size + 0xFF) & ~(unsigned int)0xFF); 130 | 131 | for (i = 0; i < g_Vmc_Image[unit].header.pages_per_cluster; i++) { 132 | 133 | if ((cluster_offset >= (g_Vmc_Image[unit].header.page_size * i)) && (cluster_offset < (g_Vmc_Image[unit].header.page_size * (i + 1)))) { 134 | 135 | Page_Num += i; 136 | Page_offset = cluster_offset - g_Vmc_Image[unit].header.page_size * i; 137 | 138 | memset(Page_Data, g_Vmc_Image[unit].erase_byte, g_Vmc_Image[unit].header.page_size); 139 | readPage(fd, Page_Data, Page_Num); 140 | 141 | if (size > g_Vmc_Image[unit].header.page_size - Page_offset) { 142 | 143 | memcpy(Page_Data + Page_offset, cluster, g_Vmc_Image[unit].header.page_size - Page_offset); 144 | writePage(fd, Page_Data, Page_Num); 145 | 146 | Page_Num++; 147 | 148 | memset(Page_Data, g_Vmc_Image[unit].erase_byte, g_Vmc_Image[unit].header.page_size); 149 | readPage(fd, Page_Data, Page_Num); 150 | 151 | memcpy(Page_Data, cluster + (g_Vmc_Image[unit].header.page_size - Page_offset), size - (g_Vmc_Image[unit].header.page_size - Page_offset)); 152 | writePage(fd, Page_Data, Page_Num); 153 | 154 | } else { 155 | 156 | memcpy(Page_Data + Page_offset, cluster, size); 157 | writePage(fd, Page_Data, Page_Num); 158 | } 159 | } 160 | } 161 | 162 | free(Page_Data); 163 | 164 | return 0; 165 | } 166 | 167 | int eraseBlock(int fd, unsigned int block) 168 | { 169 | 170 | int i, unit; 171 | u8 *Page_Data; 172 | unsigned int Page_Num; 173 | 174 | unit = (fd == g_Vmc_Image[0].fd) ? 0 : 1; 175 | 176 | Page_Data = (u8 *)malloc((g_Vmc_Image[unit].header.page_size + 0xFF) & ~(unsigned int)0xFF); 177 | 178 | Page_Num = block * g_Vmc_Image[unit].header.pages_per_block; 179 | 180 | memset(Page_Data, g_Vmc_Image[unit].erase_byte, g_Vmc_Image[unit].header.page_size); 181 | 182 | for (i = 0; i < g_Vmc_Image[unit].header.pages_per_block; i++) { 183 | 184 | writePage(fd, Page_Data, Page_Num + i); 185 | } 186 | 187 | free(Page_Data); 188 | 189 | return 0; 190 | } 191 | 192 | void *malloc(int size) 193 | { 194 | int OldState; 195 | void *result; 196 | 197 | CpuSuspendIntr(&OldState); 198 | result = AllocSysMemory(ALLOC_FIRST, size, NULL); 199 | CpuResumeIntr(OldState); 200 | 201 | return result; 202 | } 203 | 204 | void free(void *ptr) 205 | { 206 | int OldState; 207 | 208 | CpuSuspendIntr(&OldState); 209 | FreeSysMemory(ptr); 210 | CpuResumeIntr(OldState); 211 | } 212 | -------------------------------------------------------------------------------- /elf.c: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------- 2 | //File name: elf.c 3 | //-------------------------------------------------------------- 4 | #include "launchelf.h" 5 | 6 | #define MAX_PATH 1025 7 | 8 | extern u8 loader_elf[]; 9 | extern int size_loader_elf; 10 | 11 | // ELF-loading stuff 12 | #define ELF_MAGIC 0x464c457f 13 | #define ELF_PT_LOAD 1 14 | 15 | //------------------------------ 16 | typedef struct 17 | { 18 | u8 ident[16]; // struct definition for ELF object header 19 | u16 type; 20 | u16 machine; 21 | u32 version; 22 | u32 entry; 23 | u32 phoff; 24 | u32 shoff; 25 | u32 flags; 26 | u16 ehsize; 27 | u16 phentsize; 28 | u16 phnum; 29 | u16 shentsize; 30 | u16 shnum; 31 | u16 shstrndx; 32 | } elf_header_t; 33 | //------------------------------ 34 | typedef struct 35 | { 36 | u32 type; // struct definition for ELF program section header 37 | u32 offset; 38 | void *vaddr; 39 | u32 paddr; 40 | u32 filesz; 41 | u32 memsz; 42 | u32 flags; 43 | u32 align; 44 | } elf_pheader_t; 45 | //-------------------------------------------------------------- 46 | //End of data declarations 47 | //-------------------------------------------------------------- 48 | //Start of function code 49 | //-------------------------------------------------------------- 50 | // checkELFheader Tests for valid ELF file 51 | // Modified version of loader from Independence 52 | // (C) 2003 Marcus R. Brown 53 | //-------------------------------------------------------------- 54 | int checkELFheader(char *path) 55 | { 56 | elf_header_t elf_head; 57 | u8 *boot_elf = (u8 *)&elf_head; 58 | elf_header_t *eh = (elf_header_t *)boot_elf; 59 | int size = 0, ret; 60 | struct vfs_fh *fh = NULL; 61 | char fullpath[MAX_PATH], tmp[MAX_PATH], *p; 62 | 63 | strcpy(fullpath, path); 64 | if (!strncmp(fullpath, "mc", 2) || !strncmp(fullpath, "vmc", 3) || !strncmp(fullpath, "rom", 3) || !strncmp(fullpath, "cdrom", 5) || !strncmp(fullpath, "cdfs", 4)) { 65 | ; //fullpath is already correct 66 | } else if (!strncmp(fullpath, "hdd0:", 5)) { 67 | p = &path[5]; 68 | if (*p == '/') 69 | p++; 70 | sprintf(tmp, "hdd0:%s", p); 71 | p = strchr(tmp, '/'); 72 | sprintf(fullpath, "pfs0:%s", p); 73 | *p = 0; 74 | if ((ret = mountParty(tmp)) < 0) 75 | goto error; 76 | fullpath[3] += ret; 77 | } else if (!strncmp(fullpath, "bhdd0:", 6)) { 78 | p = &path[6]; 79 | if (*p == '/') 80 | p++; 81 | sprintf(tmp, "bhdd0:%s", p); 82 | p = strchr(tmp, '/'); 83 | sprintf(fullpath, "pfs0:%s", p); 84 | *p = 0; 85 | if ((ret = mountParty(tmp)) < 0) 86 | goto error; 87 | fullpath[3] += ret; 88 | } else if (!strncmp(fullpath, "mass", 4)) { 89 | char *pathSep; 90 | 91 | pathSep = strchr(path, '/'); 92 | if (pathSep && (pathSep - path < 7) && pathSep[-1] == ':') 93 | strcpy(fullpath + (pathSep - path), pathSep + 1); 94 | } else { 95 | return 0; //return 0 for unrecognized device 96 | } 97 | if ((fh = vfsOpen(fullpath, O_RDONLY)) == NULL) 98 | goto error; 99 | size = vfsLseek(fh, 0, SEEK_END); 100 | if (!size) { 101 | vfsClose(fh); 102 | goto error; 103 | } 104 | vfsLseek(fh, 0, SEEK_SET); 105 | vfsRead(fh, boot_elf, sizeof(elf_header_t)); 106 | vfsClose(fh); 107 | 108 | if ((_lw((u32)&eh->ident) != ELF_MAGIC) || eh->type != 2) 109 | goto error; 110 | 111 | return 1; //return 1 for successful check 112 | error: 113 | return -1; //return -1 for failed check 114 | } 115 | //------------------------------ 116 | //End of func: int checkELFheader(const char *path) 117 | //-------------------------------------------------------------- 118 | // RunLoaderElf loads LOADER.ELF from program memory and passes 119 | // args of selected ELF and partition to it 120 | // Modified version of loader from Independence 121 | // (C) 2003 Marcus R. Brown 122 | //------------------------------ 123 | void RunLoaderElf(char *filename, char *party) 124 | { 125 | u8 *boot_elf; 126 | elf_header_t *eh; 127 | elf_pheader_t *eph; 128 | void *pdata; 129 | int i; 130 | char *argv[2], bootpath[256]; 131 | 132 | if ((!strncmp(party, "hdd0:", 5)) && (!strncmp(filename, "pfs0:", 5))) { 133 | if (0 > fileXioMount("pfs0:", party, FIO_MT_RDONLY)) { 134 | //Some error occurred, it could be due to something else having used pfs0 135 | unmountParty(0); //So we try unmounting pfs0, to try again 136 | if (0 > fileXioMount("pfs0:", party, FIO_MT_RDONLY)) 137 | return; //If it still fails, we have to give up... 138 | } 139 | 140 | //If a path to a file on PFS is specified, change it to the standard format. 141 | //hdd0:partition:pfs:path/to/file 142 | if (strncmp(filename, "pfs0:", 5) == 0) { 143 | sprintf(bootpath, "%s:pfs:%s", party, &filename[5]); 144 | } else { 145 | sprintf(bootpath, "%s:%s", party, filename); 146 | } 147 | 148 | argv[0] = filename; 149 | argv[1] = bootpath; 150 | } else if ((!strncmp(party, "bhdd0:", 6)) && (!strncmp(filename, "pfs0:", 5))) { 151 | if (0 > fileXioMount("pfs0:", party, FIO_MT_RDONLY)) { 152 | //Some error occurred, it could be due to something else having used pfs0 153 | unmountParty(0); //So we try unmounting pfs0, to try again 154 | if (0 > fileXioMount("pfs0:", party, FIO_MT_RDONLY)) 155 | return; //If it still fails, we have to give up... 156 | } 157 | 158 | //If a path to a file on PFS is specified, change it to the standard format. 159 | //hdd0:partition:pfs:path/to/file 160 | if (strncmp(filename, "pfs0:", 5) == 0) { 161 | sprintf(bootpath, "%s:pfs:%s", party, &filename[5]); 162 | } else { 163 | sprintf(bootpath, "%s:%s", party, filename); 164 | } 165 | 166 | argv[0] = filename; 167 | argv[1] = bootpath; 168 | } else { 169 | argv[0] = filename; 170 | argv[1] = filename; 171 | } 172 | 173 | /* NB: LOADER.ELF is embedded */ 174 | boot_elf = (u8 *)loader_elf; 175 | eh = (elf_header_t *)boot_elf; 176 | if (_lw((u32)&eh->ident) != ELF_MAGIC) 177 | asm volatile("break\n"); 178 | 179 | eph = (elf_pheader_t *)(boot_elf + eh->phoff); 180 | 181 | /* Scan through the ELF's program headers and copy them into RAM, then 182 | zero out any non-loaded regions. */ 183 | for (i = 0; i < eh->phnum; i++) { 184 | if (eph[i].type != ELF_PT_LOAD) 185 | continue; 186 | 187 | pdata = (void *)(boot_elf + eph[i].offset); 188 | memcpy(eph[i].vaddr, pdata, eph[i].filesz); 189 | 190 | if (eph[i].memsz > eph[i].filesz) 191 | memset(eph[i].vaddr + eph[i].filesz, 0, 192 | eph[i].memsz - eph[i].filesz); 193 | } 194 | 195 | /* Let's go. */ 196 | SifExitRpc(); 197 | FlushCache(0); 198 | FlushCache(2); 199 | 200 | ExecPS2((void *)eh->entry, NULL, 2, argv); 201 | } 202 | //------------------------------ 203 | //End of func: void RunLoaderElf(char *filename, char *party) 204 | //-------------------------------------------------------------- 205 | //End of file: elf.c 206 | //-------------------------------------------------------------- 207 | -------------------------------------------------------------------------------- /hdl_info/hdl.c: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------- 2 | //File name: hdl.c 3 | //-------------------------------------------------------------- 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "main.h" 11 | #include "ps2_hdd.h" 12 | #include "hdd.h" 13 | #include "hdl.h" 14 | #include "apa.h" 15 | 16 | //-------------------------------------------------------------- 17 | void hdl_glist_free(hdl_games_list_t *glist) 18 | { 19 | if (glist != NULL) { 20 | free(glist->games); 21 | free(glist); 22 | } 23 | } 24 | //------------------------------ 25 | //endfunc hdl_glist_free 26 | //-------------------------------------------------------------- 27 | static int hdl_ginfo_read(hio_t *hio, const ps2_partition_header_t *part, hdl_game_info_t *ginfo) 28 | { 29 | u_long i, size; 30 | /* data we're interested in starts @ 0x101000 and is header 31 | * plus information for up to 65 partitions 32 | * (1 main + 64 sub) by 12 bytes each */ 33 | const u_long offset = 0x101000; 34 | char buffer[1024]; 35 | int result; 36 | u_long bytes; 37 | 38 | result = hio->read(hio, get_u32(&part->start) + offset / 512, 2, buffer, &bytes); 39 | if (result == 0) { 40 | if (bytes == 1024) { 41 | /* calculate total size */ 42 | size = get_u32(&part->length); 43 | for (i = 0; i < get_u32(&part->nsub); ++i) 44 | size += get_u32(&part->subs[i].length); 45 | 46 | memcpy(ginfo->partition_name, part->id, PS2_PART_IDMAX); 47 | ginfo->partition_name[PS2_PART_IDMAX] = '\0'; 48 | strcpy(ginfo->name, buffer + 8); 49 | strcpy(ginfo->startup, buffer + 0xac); 50 | ginfo->compat_flags = buffer[0xa8]; 51 | ginfo->is_dvd = buffer[0xec] == 0x14; 52 | ginfo->start_sector = get_u32(&part->start); 53 | ginfo->total_size_in_kb = size / 2; 54 | } else 55 | result = -1; 56 | } 57 | return (result); 58 | } 59 | //------------------------------ 60 | //endfunc hdl_ginfo_read 61 | //-------------------------------------------------------------- 62 | int hdl_glist_read(hio_t *hio, hdl_games_list_t **glist) 63 | { 64 | apa_partition_table_t *ptable; 65 | int result; 66 | 67 | result = apa_ptable_read_ex(hio, &ptable); 68 | if (result == 0) { 69 | u_long i, count = 0; 70 | void *tmp; 71 | for (i = 0; i < ptable->part_count; ++i) 72 | count += (get_u16(&ptable->parts[i].header.flags) == 0x00 && 73 | get_u16(&ptable->parts[i].header.type) == 0x1337); 74 | 75 | tmp = malloc(sizeof(hdl_game_info_t) * count); 76 | if (tmp != NULL) { 77 | memset(tmp, 0, sizeof(hdl_game_info_t) * count); 78 | *glist = malloc(sizeof(hdl_games_list_t)); 79 | if (*glist != NULL) { 80 | u_long index = 0; 81 | memset(*glist, 0, sizeof(hdl_games_list_t)); 82 | (*glist)->count = count; 83 | (*glist)->games = tmp; 84 | (*glist)->total_chunks = ptable->total_chunks; 85 | (*glist)->free_chunks = ptable->free_chunks; 86 | for (i = 0; result == 0 && i < ptable->part_count; ++i) { 87 | const ps2_partition_header_t *part = &ptable->parts[i].header; 88 | if (get_u16(&part->flags) == 0x00 && get_u16(&part->type) == 0x1337) 89 | result = hdl_ginfo_read(hio, part, (*glist)->games + index++); 90 | } 91 | if (result != 0) 92 | free(*glist); 93 | } else 94 | result = -2; 95 | if (result != 0) 96 | free(tmp); 97 | } else 98 | result = -2; 99 | 100 | apa_ptable_free(ptable); 101 | } else { //apa_ptable_read_ex failed 102 | } 103 | return result; 104 | } 105 | //------------------------------ 106 | //endfunc hdl_glist_read 107 | //-------------------------------------------------------------- 108 | static int hdl_ginfo_write(hio_t *hio, const ps2_partition_header_t *part, hdl_game_info_t *ginfo) 109 | { 110 | const u_long offset = 0x101000; 111 | char buffer[1024]; 112 | int result; 113 | u_long bytes; 114 | 115 | result = hio->read(hio, get_u32(&part->start) + offset / 512, 2, buffer, &bytes); 116 | 117 | memset(buffer + 8, 0, PS2_PART_NAMEMAX); 118 | memcpy(buffer + 8, ginfo->name, PS2_PART_NAMEMAX); 119 | 120 | result = hio->write(hio, get_u32(&part->start) + offset / 512, 2, buffer, &bytes); 121 | 122 | return result; 123 | } 124 | //------------------------------ 125 | //endfunc hdl_ginfo_write 126 | //-------------------------------------------------------------- 127 | int hdl_glist_write(hio_t *hio, hdl_game_info_t *ginfo) 128 | { 129 | hdl_games_list_t *tmplist; 130 | apa_partition_table_t *ptable; 131 | int result; 132 | 133 | result = apa_ptable_read_ex(hio, &ptable); 134 | if (result == 0) { 135 | u_long i, count = 0; 136 | void *tmp; 137 | for (i = 0; i < ptable->part_count; ++i) 138 | count += (get_u16(&ptable->parts[i].header.flags) == 0x00 && 139 | get_u16(&ptable->parts[i].header.type) == 0x1337); 140 | 141 | tmp = malloc(sizeof(hdl_game_info_t) * count); 142 | if (tmp != NULL) { 143 | memset(tmp, 0, sizeof(hdl_game_info_t) * count); 144 | tmplist = malloc(sizeof(hdl_games_list_t)); 145 | if (tmplist != NULL) { 146 | u_long index = 0; 147 | memset(tmplist, 0, sizeof(hdl_games_list_t)); 148 | tmplist->count = count; 149 | tmplist->games = tmp; 150 | tmplist->total_chunks = ptable->total_chunks; 151 | tmplist->free_chunks = ptable->free_chunks; 152 | for (i = 0; result == 0 && i < ptable->part_count; ++i) { 153 | const ps2_partition_header_t *part = &ptable->parts[i].header; 154 | if (get_u16(&part->flags) == 0x00 && get_u16(&part->type) == 0x1337) { 155 | result = hdl_ginfo_read(hio, part, tmplist->games + index++); 156 | if (!strcmp(tmplist->games[index - 1].partition_name, ginfo->partition_name)) { 157 | result = hdl_ginfo_write(hio, part, ginfo); 158 | break; 159 | } 160 | } 161 | } 162 | free(tmplist); 163 | } else 164 | result = -2; 165 | if (result != 0) 166 | free(tmp); 167 | } else 168 | result = -2; 169 | 170 | apa_ptable_free(ptable); 171 | } 172 | return result; 173 | } 174 | //------------------------------ 175 | //endfunc hdl_glist_write 176 | //-------------------------------------------------------------- 177 | //End of file: hdl.c 178 | //-------------------------------------------------------------- 179 | -------------------------------------------------------------------------------- /hdl_info/hdd.c: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------- 2 | //File name: hdd.c 3 | //-------------------------------------------------------------- 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "main.h" 12 | #include "ps2_hdd.h" 13 | #include "hdd.h" 14 | #include "hdl.h" 15 | #include "apa.h" 16 | 17 | static hdl_games_list_t *games = NULL; 18 | static hio_t *hio = NULL; 19 | 20 | //-------------------------------------------------------------- 21 | static int iop_stat(hio_t *hio, u_long *size_in_kb) 22 | { 23 | hio_iop_t *iop = (hio_iop_t *)hio; 24 | *size_in_kb = iop->size_in_sectors / 2; 25 | return 0; 26 | } 27 | //------------------------------ 28 | //endfunc iop_stat 29 | //-------------------------------------------------------------- 30 | static int iop_read(hio_t *hio, u_long start_sector, u_long num_sectors, void *output, u_long *bytes) 31 | { 32 | hio_iop_t *iop = (hio_iop_t *)hio; 33 | int result = ata_device_sector_io(iop->unit, output, start_sector, num_sectors, ATA_DIR_READ); 34 | if (result == 0) { 35 | *bytes = num_sectors * HDD_SECTOR_SIZE; 36 | return 0; 37 | } else 38 | return -1; 39 | } 40 | //------------------------------ 41 | //endfunc iop_read 42 | //-------------------------------------------------------------- 43 | static int iop_write(hio_t *hio, u_long start_sector, u_long num_sectors, const void *input, u_long *bytes) 44 | { 45 | hio_iop_t *iop = (hio_iop_t *)hio; 46 | int result = ata_device_sector_io(iop->unit, (char *)input, start_sector, num_sectors, ATA_DIR_WRITE); 47 | if (result == 0) { 48 | *bytes = num_sectors * HDD_SECTOR_SIZE; 49 | return 0; 50 | } 51 | return -1; 52 | } 53 | //------------------------------ 54 | //endfunc iop_write 55 | //-------------------------------------------------------------- 56 | static int iop_flush(hio_t *hio) 57 | { 58 | hio_iop_t *iop = (hio_iop_t *)hio; 59 | int result = ata_device_flush_cache(iop->unit); 60 | return result; 61 | } 62 | //------------------------------ 63 | //endfunc iop_flush 64 | //-------------------------------------------------------------- 65 | static int iop_close(hio_t *hio) 66 | { 67 | free(hio); 68 | return 0; 69 | } 70 | //------------------------------ 71 | //endfunc iop_close 72 | //-------------------------------------------------------------- 73 | static int iop_poweroff(hio_t *hio) 74 | { //Prerequisites: all files on the HDD must be saved & all partitions unmounted. 75 | dev9Shutdown(); //Power off DEV9 76 | PoweroffShutdown(); //Power off PlayStation 2 77 | return 0; 78 | } 79 | //------------------------------ 80 | //endfunc iop_poweroff 81 | //-------------------------------------------------------------- 82 | static hio_t *iop_alloc(int unit, size_t size_in_sectors) 83 | { 84 | hio_iop_t *iop = malloc(sizeof(hio_iop_t)); 85 | if (iop != NULL) { 86 | hio_t *hio = &iop->hio; 87 | hio->stat = &iop_stat; 88 | hio->read = &iop_read; 89 | hio->write = &iop_write; 90 | hio->flush = &iop_flush; 91 | hio->close = &iop_close; 92 | hio->poweroff = &iop_poweroff; 93 | iop->unit = unit; 94 | iop->size_in_sectors = size_in_sectors; 95 | } 96 | return ((hio_t *)iop); 97 | } 98 | //------------------------------ 99 | //endfunc iop_alloc 100 | //-------------------------------------------------------------- 101 | int hio_iop_probe(const char *path, hio_t **hio) 102 | { 103 | if (path[0] == 'h' && 104 | path[1] == 'd' && 105 | path[2] == 'd' && 106 | (path[3] >= '0' && path[3] <= '9') && 107 | path[4] == ':' && 108 | path[5] == '\0') { 109 | int unit = path[3] - '0'; 110 | ata_devinfo_t *dev_info = ata_get_devinfo(unit); 111 | if (dev_info != NULL && dev_info->exists) { 112 | *hio = iop_alloc(unit, dev_info->total_sectors); 113 | if (*hio != NULL) 114 | return (0); 115 | else 116 | return -2; 117 | } 118 | } 119 | return 14; 120 | } 121 | //------------------------------ 122 | //endfunc hio_iop_probe 123 | //-------------------------------------------------------------- 124 | int HdlGetGameInfo(char *PartName, GameInfo *GameInf) 125 | { 126 | 127 | int i, count = 0, err; 128 | 129 | hdl_glist_free(games); 130 | games = NULL; 131 | if (hio != NULL) 132 | hio->close(hio); 133 | hio = NULL; 134 | 135 | if (hio_iop_probe("hdd0:", &hio) == 0) { 136 | if ((err = hdl_glist_read(hio, &games)) == 0) { 137 | for (i = 0; i < games->count; ++i) { 138 | const hdl_game_info_t *game = &games->games[i]; 139 | 140 | if (!strcmp(PartName, game->partition_name)) { 141 | strcpy(GameInf->Partition_Name, game->partition_name); 142 | strcpy(GameInf->Name, game->name); 143 | strcpy(GameInf->Startup, game->startup); 144 | GameInf->Is_Dvd = game->is_dvd; 145 | return 0; //Return flag for no error 146 | } 147 | ++count; 148 | } /* for */ 149 | return -3; //Return error flag for 'Game not found' 150 | } /* if */ 151 | return err; //Return error flag for 'hdl_glist_read failed' 152 | } /* if */ 153 | return -1; //Return error flag for 'hio_iop_probe failed' 154 | } 155 | //------------------------------ 156 | //endfunc HdlGetGameInfo 157 | //-------------------------------------------------------------- 158 | 159 | int HdlRenameGame(void *Data) 160 | { 161 | 162 | int i, count = 0, err; 163 | 164 | int *Pointer = Data; 165 | Rpc_Packet_Send_Rename *Packet = (Rpc_Packet_Send_Rename *)Pointer; 166 | 167 | hdl_glist_free(games); 168 | games = NULL; 169 | if (hio != NULL) 170 | hio->close(hio); 171 | hio = NULL; 172 | 173 | if (hio_iop_probe("hdd0:", &hio) == 0) { 174 | if ((err = hdl_glist_read(hio, &games)) == 0) { 175 | for (i = 0; i < games->count; ++i) { 176 | hdl_game_info_t *game = &games->games[i]; 177 | 178 | if (!strcmp(Packet->OldName, game->name)) { 179 | printf("Renaming Game %s To %s.\n", game->name, Packet->NewName); 180 | strcpy(game->name, Packet->NewName); 181 | if ((err = hdl_glist_write(hio, game)) == 0) 182 | return 0; //Return flag for no error 183 | else 184 | return err; //Return error flag for 'hdl_glist_write failed' 185 | } 186 | ++count; 187 | } /* for */ 188 | return -3; //Return error flag for 'Game not found' 189 | } /* if */ 190 | return err; //Return error flag for 'hdl_glist_read failed' 191 | } /* if */ 192 | return -1; //Return error flag for 'hio_iop_probe failed' 193 | } 194 | //------------------------------ 195 | //endfunc HdlRenameGame 196 | //-------------------------------------------------------------- 197 | //End of file: hdd.c 198 | //-------------------------------------------------------------- 199 | -------------------------------------------------------------------------------- /hdl_info/apa.c: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------- 2 | //File name: apa.c 3 | //-------------------------------------------------------------- 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "main.h" 10 | #include "ps2_hdd.h" 11 | #include "hdd.h" 12 | #include "hdl.h" 13 | #include "apa.h" 14 | 15 | #define AUTO_DELETE_EMPTY 16 | 17 | #define _MB *(1024 * 1024) /* really ugly :-) */ 18 | 19 | typedef struct ps2_partition_run_type 20 | { 21 | unsigned long sector; 22 | u_long size_in_mb; 23 | } ps2_partition_run_t; 24 | 25 | //Remove this line, and uncomment the next line, to reactivate 'apa_check' 26 | //static int apa_check(const apa_partition_table_t *table); 27 | 28 | //-------------------------------------------------------------- 29 | u_long apa_partition_checksum(const ps2_partition_header_t *part) 30 | { 31 | const u_long *p = (const u_long *)part; 32 | register u_long i; 33 | u_long sum = 0; 34 | for (i = 1; i < 256; ++i) 35 | sum += get_u32(p + i); 36 | return sum; 37 | } 38 | //------------------------------ 39 | //endfunc apa_partition_checksum 40 | //-------------------------------------------------------------- 41 | static apa_partition_table_t *apa_ptable_alloc(void) 42 | { 43 | apa_partition_table_t *table = malloc(sizeof(apa_partition_table_t)); 44 | if (table != NULL) 45 | memset(table, 0, sizeof(apa_partition_table_t)); 46 | return table; 47 | } 48 | //------------------------------ 49 | //endfunc apa_ptable_alloc 50 | //-------------------------------------------------------------- 51 | void apa_ptable_free(apa_partition_table_t *table) 52 | { 53 | if (table != NULL) { 54 | if (table->chunks_map != NULL) 55 | free(table->chunks_map); 56 | if (table->parts != NULL) 57 | free(table->parts); 58 | free(table); 59 | } 60 | } 61 | //------------------------------ 62 | //endfunc apa_ptable_free 63 | //-------------------------------------------------------------- 64 | static int apa_part_add(apa_partition_table_t *table, const ps2_partition_header_t *part, int existing, int linked) 65 | { 66 | if (table->part_count == table->part_alloc_) { /* grow buffer */ 67 | u_long bytes = (table->part_alloc_ + 16) * sizeof(apa_partition_t); 68 | apa_partition_t *tmp = malloc(bytes); 69 | if (tmp != NULL) { 70 | memset(tmp, 0, bytes); 71 | if (table->parts != NULL) /* copy existing */ 72 | memcpy(tmp, table->parts, table->part_count * sizeof(apa_partition_t)); 73 | free(table->parts); 74 | table->parts = tmp; 75 | table->part_alloc_ += 16; 76 | } else 77 | return -2; 78 | } 79 | 80 | memcpy(&table->parts[table->part_count].header, part, sizeof(ps2_partition_header_t)); 81 | table->parts[table->part_count].existing = existing; 82 | table->parts[table->part_count].modified = !existing; 83 | table->parts[table->part_count].linked = linked; 84 | ++table->part_count; 85 | 86 | return 0; 87 | } 88 | //------------------------------ 89 | //endfunc apa_part_add 90 | //-------------------------------------------------------------- 91 | /* //Remove this line and a similar one below to reactivate 'apa_setup_statistics' 92 | static int apa_setup_statistics(apa_partition_table_t *table) 93 | { 94 | u_long i; 95 | char *map; 96 | 97 | table->total_chunks = table->device_size_in_mb / 128; 98 | map = malloc(table->total_chunks * sizeof (char)); 99 | if(map != NULL) 100 | { 101 | for(i=0; itotal_chunks; ++i) 102 | map [i] = MAP_AVAIL; 103 | 104 | // build occupided/available space map 105 | table->allocated_chunks = 0; 106 | table->free_chunks = table->total_chunks; 107 | for(i=0; ipart_count; ++i) 108 | { 109 | const ps2_partition_header_t *part = &table->parts [i].header; 110 | u_long part_no = get_u32(&part->start) / ((128 _MB) / 512); 111 | u_long num_parts = get_u32(&part->length) / ((128 _MB) / 512); 112 | 113 | // "alloc" num_parts starting at part_no 114 | while (num_parts) 115 | { 116 | if(map[part_no] == MAP_AVAIL) 117 | map[part_no] = get_u32(&part->main) == 0 ? MAP_MAIN : MAP_SUB; 118 | else 119 | map[part_no] = MAP_COLL; // collision 120 | ++part_no; 121 | --num_parts; 122 | ++table->allocated_chunks; 123 | --table->free_chunks; 124 | } 125 | } 126 | 127 | if(table->chunks_map != NULL) 128 | free(table->chunks_map); 129 | table->chunks_map = map; 130 | 131 | return 0; 132 | } 133 | else return -2; 134 | } 135 | */ 136 | //Remove this line and a similar one below to reactivate 'apa_setup_statistics' 137 | //------------------------------ 138 | //endfunc apa_setup_statistics 139 | //-------------------------------------------------------------- 140 | int apa_ptable_read_ex(hio_t *hio, apa_partition_table_t **table) 141 | { 142 | u_long size_in_kb; 143 | int result = hio->stat(hio, &size_in_kb); 144 | if (result == 0) { 145 | u_long total_sectors; 146 | // limit HDD size to 128GB - 1KB; that is: exclude the last 128MB chunk 147 | //if (size_in_kb > 128 * 1024 * 1024 - 1) 148 | // size_in_kb = 128 * 1024 * 1024 - 1; 149 | 150 | total_sectors = size_in_kb * 2; /* 1KB = 2 sectors of 512 bytes, each */ 151 | 152 | *table = apa_ptable_alloc(); 153 | if (*table != NULL) { 154 | u_long sector = 0; 155 | do { 156 | u_long bytes; 157 | ps2_partition_header_t part; 158 | result = hio->read(hio, sector, sizeof(part) / 512, &part, &bytes); 159 | if (result == 0) { 160 | if (bytes == sizeof(part) && 161 | get_u32(&part.checksum) == apa_partition_checksum(&part) && 162 | memcmp(part.magic, PS2_PARTITION_MAGIC, 4) == 0) { 163 | if (get_u32(&part.start) < total_sectors && 164 | get_u32(&part.start) + get_u32(&part.length) < total_sectors) { 165 | if ((get_u16(&part.flags) == 0x0000) && (get_u16(&part.type) == 0x1337)) 166 | result = apa_part_add(*table, &part, 1, 1); 167 | if (result == 0) 168 | sector = get_u32(&part.next); 169 | } else { /* partition behind end-of-HDD */ 170 | result = 7; /* data behind end-of-HDD */ 171 | break; 172 | } 173 | } else 174 | result = 1; 175 | } 176 | /* TODO: check whether next partition is not loaded already -- 177 | * do not deadlock; that is a quick-and-dirty hack */ 178 | if ((*table)->part_count > 10000) 179 | result = 7; 180 | } while (result == 0 && sector != 0); 181 | 182 | if (result == 0) { 183 | (*table)->device_size_in_mb = size_in_kb / 1024; 184 | //NB: uncommenting the next lines requires changes elsewhere too 185 | //result = apa_setup_statistics (*table); 186 | //if (result == 0) 187 | //result = apa_check (*table); 188 | } 189 | 190 | if (result != 0) { 191 | result = 20000 + (*table)->part_count; 192 | apa_ptable_free(*table); 193 | } 194 | } else 195 | result = -2; 196 | } 197 | return result; 198 | } 199 | //------------------------------ 200 | //endfunc apa_ptable_read_ex 201 | //-------------------------------------------------------------- 202 | /* //Remove this line and a similar one below to reactivate 'apa_check' 203 | static int apa_check(const apa_partition_table_t *table) 204 | { 205 | 206 | u_long i, j, k; 207 | 208 | const u_long total_sectors = table->device_size_in_mb * 1024 * 2; 209 | 210 | for (i = 0; i < table->part_count; ++i) { 211 | const ps2_partition_header_t *part = &table->parts[i].header; 212 | if (get_u32(&part->checksum) != apa_partition_checksum(part)) 213 | return 7; // bad checksum 214 | 215 | if (get_u32(&part->start) < total_sectors && 216 | get_u32(&part->start) + get_u32(&part->length) <= total_sectors) 217 | ; 218 | else { 219 | return 7; // data behind end-of-HDD 220 | } 221 | 222 | if ((get_u32(&part->length) % ((128 _MB) / 512)) != 0) 223 | return 7; // partition size not multiple to 128MB 224 | 225 | if ((get_u32(&part->start) % get_u32(&part->length)) != 0) 226 | return 7; // partition start not multiple on partition size 227 | 228 | if (get_u32(&part->main) == 0 && 229 | get_u16(&part->flags) == 0 && 230 | get_u32(&part->start) != 0) { // check sub-partitions 231 | u_long count = 0; 232 | for (j = 0; j < table->part_count; ++j) { 233 | const ps2_partition_header_t *part2 = &table->parts[j].header; 234 | if (get_u32(&part2->main) == get_u32(&part->start)) { // sub-partition of current main partition 235 | int found; 236 | if (get_u16(&part2->flags) != PS2_PART_FLAG_SUB) 237 | return 7; 238 | 239 | found = 0; 240 | for (k = 0; k < get_u32(&part->nsub); ++k) 241 | if (get_u32(&part->subs[k].start) == get_u32(&part2->start)) { // in list 242 | if (get_u32(&part->subs[k].length) != get_u32(&part2->length)) 243 | return 7; 244 | found = 1; 245 | break; 246 | } 247 | if (!found) 248 | return 7; // not found in the list 249 | 250 | ++count; 251 | } 252 | } 253 | if (count != get_u32(&part->nsub)) 254 | return 7; // wrong number of sub-partitions 255 | } 256 | } 257 | 258 | // verify double-linked list 259 | for (i = 0; i < table->part_count; ++i) { 260 | apa_partition_t *prev = table->parts + (i > 0 ? i - 1 : table->part_count - 1); 261 | apa_partition_t *curr = table->parts + i; 262 | apa_partition_t *next = table->parts + (i + 1 < table->part_count ? i + 1 : 0); 263 | if (get_u32(&curr->header.prev) != get_u32(&prev->header.start) || 264 | get_u32(&curr->header.next) != get_u32(&next->header.start)) 265 | return 7; // bad links 266 | } 267 | 268 | return 0; 269 | } 270 | */ 271 | //Remove this line and a similar one above to reactivate 'apa_check' 272 | //------------------------------ 273 | //endfunc apa_check 274 | //-------------------------------------------------------------- 275 | u_long get_u32(const void *buffer) 276 | { 277 | const u_char *p = buffer; 278 | return ((((u_long)p[3]) << 24) | 279 | (((u_long)p[2]) << 16) | 280 | (((u_long)p[1]) << 8) | 281 | (((u_long)p[0]) << 0)); 282 | } 283 | //------------------------------ 284 | //endfunc get_u32 285 | //-------------------------------------------------------------- 286 | void set_u32(void *buffer, u_long val) 287 | { 288 | u_char *p = buffer; 289 | p[3] = (u_char)(val >> 24); 290 | p[2] = (u_char)(val >> 16); 291 | p[1] = (u_char)(val >> 8); 292 | p[0] = (u_char)(val >> 0); 293 | } 294 | //------------------------------ 295 | //endfunc set_u32 296 | //-------------------------------------------------------------- 297 | u_short get_u16(const void *buffer) 298 | { 299 | const u_char *p = buffer; 300 | return ((((u_short)p[1]) << 8) | 301 | (((u_short)p[0]) << 0)); 302 | } 303 | //------------------------------ 304 | //endfunc get_u16 305 | //-------------------------------------------------------------- 306 | void set_u16(void *buffer, u_short val) 307 | { 308 | u_char *p = buffer; 309 | p[1] = (u_char)(val >> 8); 310 | p[0] = (u_char)(val >> 0); 311 | } 312 | //------------------------------ 313 | //endfunc set_u16 314 | //-------------------------------------------------------------- 315 | //End of file: apa.c 316 | //-------------------------------------------------------------- 317 | -------------------------------------------------------------------------------- /vmc_fs/vmc.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // Define this to enable debugging, will later support debugging levels, so only messages greater then a certain level will be displayed 12 | //#define DEBUG 8 13 | //For release versions of uLE, DEBUG should not be defined 14 | //To avoid slowdown and size bloat 15 | 16 | // Define this to enable some basic profiling support, each function will display the time it took to run. 17 | // #define PROFILING 18 | 19 | 20 | // Memory allocation helpers. 21 | void *malloc(int size); 22 | void free(void *ptr); 23 | 24 | #define TRUE 1 25 | #define FALSE 0 26 | 27 | #define MAX_NAME 32 28 | #define MAX_PATH 1024 29 | 30 | 31 | // Vmc_fs error definitions 32 | #define VMCFS_ERR_NO 0 33 | #define VMCFS_ERR_INITIALIZED -1 34 | #define VMCFS_ERR_VMC_OPEN -2 35 | #define VMCFS_ERR_VMC_READ -3 36 | #define VMCFS_ERR_CARD_TYPE -4 37 | #define VMCFS_ERR_NOT_FORMATED -5 38 | #define VMCFS_ERR_VMC_SIZE -6 39 | #define VMCFS_ERR_NOT_MOUNT -7 40 | #define VMCFS_ERR_MOUNT_BUSY -8 41 | #define VMCFS_ERR_IMPLEMENTED -9 42 | 43 | 44 | // The devctl commands: 0x56 == V, 0x4D == M, 0x43 == C, 0x01, 0x02, ... == command number. 45 | #define DEVCTL_VMCFS_CLEAN 0x564D4301 // Set as free all fat cluster corresponding to a none existing object. ( Object are just marked as none existing but not removed from fat table when rmdir or remove fonctions are call. This allow to recover a deleted file. ) 46 | #define DEVCTL_VMCFS_CKFREE 0x564D4302 // Check free space available on vmc. 47 | 48 | // The ioctl commands: 0x56 == V, 0x4D == M, 0x43 == C, 0x01, 0x02, ... == command number. 49 | #define IOCTL_VMCFS_RECOVER 0x564D4303 // Recover an object marked as none existing. ( data must be a valid path to an object in vmc file ) 50 | 51 | 52 | // Vmc format enum 53 | typedef enum { 54 | FORMAT_FULL, 55 | FORMAT_FAST 56 | } Vmc_Format_Enum; 57 | 58 | 59 | // Memorycard type definitions 60 | #define PSX_MEMORYCARD 0x1 61 | #define PS2_MEMORYCARD 0x2 62 | #define PDA_MEMORYCARD 0x3 63 | 64 | // Directory Entry Mode Flags 65 | #define DF_READ 0x0001 // Read permission. 66 | #define DF_WRITE 0x0002 // Write permission. 67 | #define DF_EXECUTE 0x0004 // Execute permission. 68 | #define DF_PROTECTED 0x0008 // Directory is copy protected. 69 | #define DF_FILE 0x0010 // Regular file. 70 | #define DF_DIRECTORY 0x0020 // Directory. 71 | #define DF_040 0x0040 // Used internally to create directories. 72 | #define DF_080 0x0080 // Copied? 73 | #define DF_0100 0x0100 // - 74 | #define O_CREAT 0x0200 // Used to create files. 75 | #define DF_0400 0x0400 // Set when files and directories are created, otherwise ignored. 76 | #define DF_POCKETSTN 0x0800 // PocketStation application save file. 77 | #define DF_PSX 0x1000 // PlayStation save file. 78 | #define DF_HIDDEN 0x2000 // File is hidden. 79 | #define DF_04000 0x4000 // - 80 | #define DF_EXISTS 0x8000 // This entry is in use. If this flag is clear, then the file or directory has been deleted. 81 | 82 | 83 | // Cluster definitions 84 | #define MAX_CLUSTER_SIZE 0x400 85 | 86 | #define ROOT_CLUSTER 0x00000000 87 | #define FREE_CLUSTER 0x7FFFFFFF 88 | #define EOF_CLUSTER 0xFFFFFFFF 89 | #define ERROR_CLUSTER 0xFFFFFFFF 90 | #define NOFOUND_CLUSTER 0xFFFFFFFF 91 | #define MASK_CLUSTER 0x80000000 92 | 93 | 94 | // The debugging functions, very very handy 95 | #ifdef DEBUG 96 | #define DEBUGPRINT(level, args...) \ 97 | if (DEBUG >= level) \ 98 | printf(args) 99 | #else 100 | #define DEBUGPRINT(args...) 101 | #endif 102 | 103 | 104 | // Used for timing functions, use this to optimize stuff 105 | #ifdef PROFILING 106 | void profilerStart(iop_sys_clock_t *iopclock); 107 | void profilerEnd(const char *function, const char *name, iop_sys_clock_t *iopclock1); 108 | //This creates 2 variables with the names name1/name2, and starts the profiler 109 | #define PROF_START(name) \ 110 | iop_sys_clock_t name; \ 111 | profilerStart(&name); 112 | //this takes the 2 variable names and ends the profiler, printing the time taken 113 | #define PROF_END(name) \ 114 | profilerEnd(__func__, #name, &name); 115 | #else 116 | //define away the profiler functions 117 | #define PROF_START(args) ; 118 | #define PROF_END(args) ; 119 | #endif 120 | 121 | 122 | // Global Structures Defintions 123 | 124 | // General data struct shared by both files / folders that we have opened 125 | struct gen_privdata 126 | { 127 | int fd; 128 | unsigned int indir_fat_clusters[32]; 129 | unsigned int first_allocatable; 130 | unsigned int last_allocatable; 131 | unsigned char dirent_page; 132 | }; 133 | 134 | // the structure used by files that we have opened 135 | struct file_privdata 136 | { 137 | struct gen_privdata gendata; 138 | unsigned int file_startcluster; 139 | unsigned int file_length; 140 | unsigned int file_position; 141 | unsigned int file_cluster; 142 | unsigned int cluster_offset; 143 | unsigned int file_dirpage; 144 | }; 145 | 146 | // the structure used by directories that we have opened 147 | struct dir_privdata 148 | { 149 | struct gen_privdata gendata; 150 | unsigned int dir_number; // first or second entry in the cluster? 151 | unsigned int dir_cluster; // what cluster we are currently reading directory entries from 152 | unsigned int dir_length; // the length of the directory 153 | }; 154 | 155 | // date / time descriptor 156 | typedef struct 157 | { 158 | unsigned char unused0; 159 | unsigned char sec; 160 | unsigned char min; 161 | unsigned char hour; 162 | unsigned char day; 163 | unsigned char month; 164 | unsigned short year; 165 | } vmc_datetime; 166 | 167 | // the structure of a directory entry 168 | struct direntry 169 | { 170 | unsigned short mode; // See directory mode definitions. 171 | unsigned char unused0[2]; // - 172 | unsigned int length; // Length in bytes if a file, or entries if a directory. 173 | vmc_datetime created; // created time. 174 | unsigned int cluster; // First cluster of the file, or 0xFFFFFFFF for an empty file. In "." entries it's the first cluster of the parent directory relative to first_allocatable. 175 | unsigned int dir_entry; // Only in "." entries. Entry of this directory in its parent's directory. 176 | vmc_datetime modified; // Modification time. 177 | unsigned int attr; // User defined attribute. 178 | unsigned char unused1[28]; // - 179 | char name[32]; // Zero terminated name for this directory entry. 180 | unsigned char unused2[416]; // - 181 | }; 182 | 183 | // A structure containing all of the information about the superblock on a memory card. 184 | struct superblock 185 | { 186 | unsigned char magic[40]; 187 | unsigned short page_size; 188 | unsigned short pages_per_cluster; 189 | unsigned short pages_per_block; 190 | unsigned short unused0; // always 0xFF00 191 | unsigned int clusters_per_card; 192 | unsigned int first_allocatable; 193 | unsigned int last_allocatable; 194 | unsigned int root_cluster; // must be 0 195 | unsigned int backup_block1; // 1023 196 | unsigned int backup_block2; // 1024 197 | unsigned char unused1[8]; // unused / who knows what it is 198 | unsigned int indir_fat_clusters[32]; 199 | unsigned int bad_block_list[32]; 200 | unsigned char mc_type; 201 | unsigned char mc_flag; 202 | unsigned short unused2; // zero 203 | unsigned int cluster_size; // 1024 always, 0x400 204 | unsigned int unused3; // 0x100 205 | unsigned int size_in_megs; // size in megabytes 206 | unsigned int unused4; // 0xffffffff 207 | unsigned char unused5[12]; // zero 208 | unsigned int max_used; // 97%of total clusters 209 | unsigned char unused6[8]; // zero 210 | unsigned int unused7; // 0xffffffff 211 | }; 212 | 213 | // General vmc image structure 214 | struct global_vmc 215 | { 216 | int fd; // global descriptor 217 | struct superblock header; // superblock header 218 | int formated; // card is formated 219 | int ecc_flag; // ecc data found in vmc file 220 | unsigned int card_size; // vmc file size 221 | unsigned int total_pages; // total number of pages in the vmc file 222 | unsigned int cluster_size; // size in byte of a cluster 223 | unsigned short erase_byte; // erased blocks have all bits set to 0x0 or 0xFF 224 | unsigned int last_idc; // last indirect cluster 225 | unsigned int last_cluster; // last cluster 226 | unsigned int indirect_cluster[MAX_CLUSTER_SIZE]; // indirect fat cluster 227 | unsigned int fat_cluster[MAX_CLUSTER_SIZE]; // fat cluster 228 | unsigned int last_free_cluster; // adress of the last free cluster found when getting free cluster 229 | }; 230 | 231 | 232 | extern struct global_vmc g_Vmc_Image[2]; 233 | extern int g_Vmc_Format_Mode; 234 | extern int g_Vmc_Initialized; 235 | 236 | 237 | // vmc_fs.c 238 | int Vmc_Initialize(iop_device_t *driver); 239 | int Vmc_Deinitialize(iop_device_t *driver); 240 | 241 | // vmc_io.c 242 | int Vmc_Format(iop_file_t *, const char *dev, const char *blockdev, void *arg, int arglen); 243 | int Vmc_Open(iop_file_t *f, const char *name, int flags, int mode); 244 | int Vmc_Close(iop_file_t *f); 245 | int Vmc_Read(iop_file_t *f, void *buffer, int size); 246 | int Vmc_Write(iop_file_t *f, void *buffer, int size); 247 | int Vmc_Lseek(iop_file_t *f, int offset, int whence); 248 | int Vmc_Ioctl(iop_file_t *f, int cmd, void *data); 249 | int Vmc_Remove(iop_file_t *f, const char *path); 250 | int Vmc_Mkdir(iop_file_t *f, const char *path1, int mode); 251 | int Vmc_Rmdir(iop_file_t *f, const char *path1); 252 | int Vmc_Dopen(iop_file_t *f, const char *path); 253 | int Vmc_Dclose(iop_file_t *f); 254 | int Vmc_Dread(iop_file_t *f, iox_dirent_t *buf); 255 | int Vmc_Getstat(iop_file_t *f, const char *path, iox_stat_t *stat); 256 | int Vmc_Chstat(iop_file_t *f, const char *path, iox_stat_t *stat, unsigned int statmask); 257 | int Vmc_Rename(iop_file_t *f, const char *path, const char *new_name); 258 | int Vmc_Chdir(iop_file_t *f, const char *path); 259 | int Vmc_Sync(iop_file_t *f, const char *device, int flag); 260 | int Vmc_Mount(iop_file_t *f, const char *fsname, const char *devname, int flag, void *arg, int arg_len); 261 | int Vmc_Umount(iop_file_t *f, const char *fsname); 262 | s64 Vmc_Lseek64(iop_file_t *f, s64 offset, int whence); 263 | int Vmc_Devctl(iop_file_t *f, const char *path, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen); 264 | int Vmc_Symlink(iop_file_t *f, const char *old, const char *new); 265 | int Vmc_Readlink(iop_file_t *f, const char *path, char *buf, unsigned int buf_len); 266 | int Vmc_Ioctl2(iop_file_t *f, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen); 267 | int Vmc_Recover(int unit, const char *path1); 268 | unsigned int Vmc_Checkfree(int unit); 269 | int Vmc_Clean(int unit); 270 | 271 | // mcfat.c 272 | typedef enum { 273 | FAT_VALUE, 274 | FAT_MASK 275 | } GetFat_Mode; 276 | 277 | typedef enum { 278 | FAT_RESET, 279 | FAT_SET 280 | } SetFat_Mode; 281 | 282 | unsigned int getFatEntry(int fd, unsigned int cluster, unsigned int *indir_fat_clusters, GetFat_Mode Mode); 283 | unsigned int setFatEntry(int fd, unsigned int cluster, unsigned int value, unsigned int *indir_fat_clusters, SetFat_Mode Mode); 284 | 285 | 286 | // ps2.c 287 | int eraseBlock(int fd, unsigned int block); 288 | int writePage(int fd, u8 *page, unsigned int pagenum); 289 | int writeCluster(int fd, u8 *cluster, unsigned int clusternum); 290 | int writeClusterPart(int fd, u8 *cluster, unsigned int clusternum, int cluster_offset, int size); 291 | int readPage(int fd, u8 *page, unsigned int pagenum); 292 | int readCluster(int fd, u8 *cluster, unsigned int clusternum); 293 | 294 | 295 | // misc.c 296 | unsigned int getDirentryFromPath(struct direntry *retval, const char *path, struct gen_privdata *gendata, int unit); 297 | unsigned int addObject(struct gen_privdata *gendata, unsigned int parentcluster, struct direntry *parent, struct direntry *dirent, int unit); 298 | void removeObject(struct gen_privdata *gendata, unsigned int dirent_cluster, struct direntry *dirent, int unit); 299 | unsigned int getFreeCluster(struct gen_privdata *gendata, int unit); 300 | int getPs2Time(vmc_datetime *tm); 301 | int setDefaultSpec(int unit); 302 | void buildECC(int unit, const u8 *Page_Data, u8 *ECC_Data); 303 | -------------------------------------------------------------------------------- /pad.c: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------- 2 | // File name: pad.c 3 | //--------------------------------------------------------------------------- 4 | #include "launchelf.h" 5 | 6 | static char padBuf_t[2][256] __attribute__((aligned(64))); 7 | struct padButtonStatus buttons_t[2]; 8 | u32 padtype_t[2]; 9 | u32 paddata, paddata_t[2]; 10 | u32 old_pad = 0, old_pad_t[2] = {0, 0}; 11 | u32 new_pad, new_pad_t[2]; 12 | u32 joy_value = 0; 13 | static int test_joy = 0; 14 | 15 | //--------------------------------------------------------------------------- 16 | // read PAD, without KB, and allow no auto-repeat. This is needed in code 17 | // that is used regardless of VSync cycles, and where KB is not wanted. 18 | //--------------------------------------------------------------------------- 19 | int readpad_noKBnoRepeat(void) 20 | { 21 | int port, state, ret[2]; 22 | 23 | for (port = 0; port < 2; port++) { 24 | if ((state = padGetState(port, 0)) == PAD_STATE_STABLE || (state == PAD_STATE_FINDCTP1)) { 25 | //Deal with cases where pad state is valid for padRead 26 | ret[port] = padRead(port, 0, &buttons_t[port]); 27 | if (ret[port] != 0) { 28 | paddata_t[port] = 0xffff ^ buttons_t[port].btns; 29 | new_pad_t[port] = paddata_t[port] & ~old_pad_t[port]; 30 | old_pad_t[port] = paddata_t[port]; 31 | } 32 | } else { 33 | //Deal with cases where pad state is not valid for padRead 34 | new_pad_t[port] = 0; 35 | } //ends 'if' testing for state valid for padRead 36 | } //ends for 37 | new_pad = new_pad_t[0] | new_pad_t[1]; //This has only new button bits 38 | paddata = paddata_t[0] | paddata_t[1]; //This has all pressed button bits 39 | return (ret[0] | ret[1]); 40 | } 41 | //------------------------------ 42 | //endfunc readpad_noKBnoRepeat 43 | //--------------------------------------------------------------------------- 44 | // read PAD, but ignore KB. This is needed in code with own KB handlers, 45 | // such as the virtual keyboard input routines for 'Rename' and 'New Dir' 46 | //--------------------------------------------------------------------------- 47 | int readpad_no_KB(void) 48 | { 49 | static u64 rpt_time[2] = {0, 0}; 50 | static int rpt_count[2]; 51 | int port, state, ret[2]; 52 | 53 | for (port = 0; port < 2; port++) { 54 | if ((state = padGetState(port, 0)) == PAD_STATE_STABLE || (state == PAD_STATE_FINDCTP1)) { 55 | //Deal with cases where pad state is valid for padRead 56 | ret[port] = padRead(port, 0, &buttons_t[port]); 57 | if (ret[port] != 0) { 58 | paddata_t[port] = 0xffff ^ buttons_t[port].btns; 59 | if ((padtype_t[port] == 2) && (1 & (test_joy++))) { //DualShock && time for joy scan 60 | joy_value = 0; 61 | if (buttons_t[port].rjoy_h >= 0xbf) { 62 | paddata_t[port] = PAD_R3_H1; 63 | joy_value = buttons_t[port].rjoy_h - 0xbf; 64 | } else if (buttons_t[port].rjoy_h <= 0x40) { 65 | paddata_t[port] = PAD_R3_H0; 66 | joy_value = -(buttons_t[port].rjoy_h - 0x40); 67 | } else if (buttons_t[port].rjoy_v <= 0x40) { 68 | paddata_t[port] = PAD_R3_V0; 69 | joy_value = -(buttons_t[port].rjoy_v - 0x40); 70 | } else if (buttons_t[port].rjoy_v >= 0xbf) { 71 | paddata_t[port] = PAD_R3_V1; 72 | joy_value = buttons_t[port].rjoy_v - 0xbf; 73 | } else if (buttons_t[port].ljoy_h >= 0xbf) { 74 | paddata_t[port] = PAD_L3_H1; 75 | joy_value = buttons_t[port].ljoy_h - 0xbf; 76 | } else if (buttons_t[port].ljoy_h <= 0x40) { 77 | paddata_t[port] = PAD_L3_H0; 78 | joy_value = -(buttons_t[port].ljoy_h - 0x40); 79 | } else if (buttons_t[port].ljoy_v <= 0x40) { 80 | paddata_t[port] = PAD_L3_V0; 81 | joy_value = -(buttons_t[port].ljoy_v - 0x40); 82 | } else if (buttons_t[port].ljoy_v >= 0xbf) { 83 | paddata_t[port] = PAD_L3_V1; 84 | joy_value = buttons_t[port].ljoy_v - 0xbf; 85 | } 86 | } 87 | new_pad_t[port] = paddata_t[port] & ~old_pad_t[port]; 88 | if (old_pad_t[port] == paddata_t[port]) { 89 | //no change of pad data 90 | if (Timer() > rpt_time[port]) { 91 | new_pad_t[port] = paddata_t[port]; //Accept repeated buttons as new 92 | rpt_time[port] = Timer() + 40; //Min delay = 40ms => 25Hz repeat 93 | if (rpt_count[port]++ < 20) 94 | rpt_time[port] += 43; //Early delays = 83ms => 12Hz repeat 95 | } 96 | } else { 97 | //pad data has changed ! 98 | rpt_count[port] = 0; 99 | rpt_time[port] = Timer() + 400; //Init delay = 400ms 100 | old_pad_t[port] = paddata_t[port]; 101 | } 102 | } 103 | } else { 104 | //Deal with cases where pad state is not valid for padRead 105 | //NB: This should NOT clear KB repeat test variables 106 | new_pad_t[port] = 0; 107 | //old_pad_t[port]=0; //Clearing this could cause hasty repeats 108 | } //ends 'if' testing for state valid for padRead 109 | } //ends for 110 | new_pad = new_pad_t[0] | new_pad_t[1]; 111 | paddata = paddata_t[0] | paddata_t[1]; //This has all pressed button bits 112 | return (ret[0] | ret[1]); 113 | } 114 | //------------------------------ 115 | //endfunc readpad_no_KB 116 | //--------------------------------------------------------------------------- 117 | // simPadKB attempts reading data from a USB keyboard, and map this as a 118 | // virtual gamepad. (Very improvised and sloppy, but it should work fine.) 119 | //--------------------------------------------------------------------------- 120 | int simPadKB(void) 121 | { 122 | int ret, command; 123 | char KeyPress; 124 | 125 | if ((!setting->usbkbd_used) || (!PS2KbdRead(&KeyPress))) 126 | return 0; 127 | if (KeyPress != PS2KBD_ESCAPE_KEY) 128 | command = KeyPress; 129 | else { 130 | PS2KbdRead(&KeyPress); 131 | command = 0x100 + KeyPress; 132 | } 133 | ret = 1; //Assume that the entered key is a valid command 134 | switch (command) { 135 | case 0x11B: //Escape == Triangle 136 | new_pad = PAD_TRIANGLE; 137 | break; 138 | case 0x00A: //Enter == OK 139 | if (!swapKeys) 140 | new_pad = PAD_CIRCLE; 141 | else 142 | new_pad = PAD_CROSS; 143 | break; 144 | case 0x020: //Space == Cancel/Mark 145 | if (!swapKeys) 146 | new_pad = PAD_CROSS; 147 | else 148 | new_pad = PAD_CIRCLE; 149 | break; 150 | case 0x031: //'1' == L1 151 | new_pad = PAD_L1; 152 | break; 153 | case 0x032: //'2' == L2 154 | new_pad = PAD_L2; 155 | break; 156 | case 0x033: //'3' == L3 157 | new_pad = PAD_L3; 158 | break; 159 | case 0x077: //'w' == Up 160 | new_pad = PAD_UP; 161 | break; 162 | case 0x061: //'a' == Left 163 | new_pad = PAD_LEFT; 164 | break; 165 | case 0x073: //'s' == Right 166 | new_pad = PAD_RIGHT; 167 | break; 168 | case 0x07A: //'z' == Down 169 | new_pad = PAD_DOWN; 170 | break; 171 | case 0x030: //'0' == R1 172 | new_pad = PAD_R1; 173 | break; 174 | case 0x039: //'9' == R2 175 | new_pad = PAD_R2; 176 | break; 177 | case 0x038: //'8' == R3 178 | new_pad = PAD_R3; 179 | break; 180 | case 0x069: //'i' == Triangle 181 | new_pad = PAD_TRIANGLE; 182 | break; 183 | case 0x06A: //'j' == Square 184 | new_pad = PAD_SQUARE; 185 | break; 186 | case 0x06B: //'k' == Circle 187 | new_pad = PAD_CIRCLE; 188 | break; 189 | case 0x06D: //'m' == Cross 190 | new_pad = PAD_CROSS; 191 | break; 192 | case 0x101: //F1 == L1 193 | new_pad = PAD_L1; 194 | break; 195 | case 0x102: //F2 == L2 196 | new_pad = PAD_L2; 197 | break; 198 | case 0x103: //F3 == L3 199 | new_pad = PAD_L3; 200 | break; 201 | case 0x12C: //Up == Up 202 | new_pad = PAD_UP; 203 | break; 204 | case 0x12A: //Left == Left 205 | new_pad = PAD_LEFT; 206 | break; 207 | case 0x129: //Right == Right 208 | new_pad = PAD_RIGHT; 209 | break; 210 | case 0x12B: //Down == Down 211 | new_pad = PAD_DOWN; 212 | break; 213 | case 0x123: //Insert == Select 214 | new_pad = PAD_SELECT; 215 | break; 216 | case 0x10C: //F12 == R1 217 | new_pad = PAD_R1; 218 | break; 219 | case 0x10B: //F11 == R2 220 | new_pad = PAD_R2; 221 | break; 222 | case 0x10A: //F10 == R3 223 | new_pad = PAD_R3; 224 | break; 225 | case 0x124: //Home == Triangle 226 | new_pad = PAD_TRIANGLE; 227 | break; 228 | case 0x127: //End == Square 229 | new_pad = PAD_SQUARE; 230 | break; 231 | case 0x125: //PgUp == Circle 232 | new_pad = PAD_CIRCLE; 233 | break; 234 | case 0x128: //PgDn == Cross 235 | new_pad = PAD_CROSS; 236 | break; 237 | case 0x126: //Delete == Start 238 | new_pad = PAD_START; 239 | break; 240 | default: //Unrecognized key => no pad button 241 | ret = 0; 242 | break; 243 | } 244 | return ret; 245 | } 246 | //------------------------------ 247 | //endfunc simPadKB 248 | //--------------------------------------------------------------------------- 249 | // readpad will call readpad_no_KB, and if no new pad buttons are found, it 250 | // will also attempt reading data from a USB keyboard, and map this as a 251 | // virtual gamepad. (Very improvised and sloppy, but it should work fine.) 252 | //--------------------------------------------------------------------------- 253 | int readpad(void) 254 | { 255 | int ret; 256 | 257 | if ((ret = readpad_no_KB()) && new_pad) 258 | return ret; 259 | 260 | return simPadKB(); 261 | } 262 | //------------------------------ 263 | //endfunc readpad 264 | //--------------------------------------------------------------------------- 265 | // readpad_noRepeat calls readpad_noKBnoRepeat, and if no new pad buttons are 266 | // found, it also attempts reading data from a USB keyboard, and map this as 267 | // a virtual gamepad. (Very improvised and sloppy, but it should work fine.) 268 | //--------------------------------------------------------------------------- 269 | int readpad_noRepeat(void) 270 | { 271 | int ret; 272 | 273 | if ((ret = readpad_noKBnoRepeat()) && new_pad) 274 | return ret; 275 | 276 | return simPadKB(); 277 | } 278 | //------------------------------ 279 | //endfunc readpad_noRepeat 280 | //--------------------------------------------------------------------------- 281 | // Wait for specific PAD, but also accept disconnected state 282 | void waitPadReady(int port, int slot) 283 | { 284 | int state, lastState; 285 | char stateString[16]; 286 | 287 | state = padGetState(port, slot); 288 | lastState = -1; 289 | while ((state != PAD_STATE_DISCONN) && (state != PAD_STATE_STABLE) && (state != PAD_STATE_FINDCTP1)) { 290 | if (state != lastState) 291 | padStateInt2String(state, stateString); 292 | lastState = state; 293 | state = padGetState(port, slot); 294 | } 295 | } 296 | //--------------------------------------------------------------------------- 297 | // Wait for any PAD, but also accept disconnected states 298 | void waitAnyPadReady(void) 299 | { 300 | int state_1, state_2; 301 | 302 | state_1 = padGetState(0, 0); 303 | state_2 = padGetState(1, 0); 304 | while ((state_1 != PAD_STATE_DISCONN) && (state_2 != PAD_STATE_DISCONN) && (state_1 != PAD_STATE_STABLE) && (state_2 != PAD_STATE_STABLE) && (state_1 != PAD_STATE_FINDCTP1) && (state_2 != PAD_STATE_FINDCTP1)) { 305 | state_1 = padGetState(0, 0); 306 | state_2 = padGetState(1, 0); 307 | } 308 | } 309 | //--------------------------------------------------------------------------- 310 | // setup PAD 311 | int setupPad(void) 312 | { 313 | int ret, i, port, state, modes; 314 | 315 | padInit(0); 316 | 317 | for (port = 0; port < 2; port++) { 318 | padtype_t[port] = 0; //Assume that we don't have a proper PS2 controller 319 | if ((ret = padPortOpen(port, 0, &padBuf_t[port][0])) == 0) 320 | return 0; 321 | waitPadReady(port, 0); 322 | state = padGetState(port, 0); 323 | if (state != PAD_STATE_DISCONN) { //if anything connected to this port 324 | modes = padInfoMode(port, 0, PAD_MODETABLE, -1); 325 | if (modes != 0) { //modes != 0, so it may be a dualshock type 326 | for (i = 0; i < modes; i++) { 327 | if (padInfoMode(port, 0, PAD_MODETABLE, i) == PAD_TYPE_DUALSHOCK) { 328 | padtype_t[port] = 2; //flag normal PS2 controller 329 | break; 330 | } 331 | } //ends for (modes) 332 | } else { //modes == 0, so this is a digital controller 333 | padtype_t[port] = 1; //flag digital controller 334 | } 335 | if (padtype_t[port] == 2) //if DualShock 336 | padSetMainMode(port, 0, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK); //Set DualShock 337 | else //else 338 | padSetMainMode(port, 0, PAD_MMODE_DIGITAL, PAD_MMODE_UNLOCK); //Set Digital 339 | waitPadReady(port, 0); //Await completion 340 | } else { //Nothing is connected to this port 341 | padSetMainMode(port, 0, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK); //Fake DualShock 342 | waitPadReady(port, 0); //Await completion 343 | } 344 | } //ends for (port) 345 | return 1; 346 | } 347 | //--------------------------------------------------------------------------- 348 | // End of file: pad.c 349 | //--------------------------------------------------------------------------- 350 | -------------------------------------------------------------------------------- /launchelf.h: -------------------------------------------------------------------------------- 1 | #ifndef LAUNCHELF_H 2 | #define LAUNCHELF_H 3 | 4 | #define ULE_VERSION "v4.43a" 5 | //#ifndef ULE_VERDATE 6 | //#define ULE_VERDATE __DATE__ 7 | //#endif 8 | #include "githash.h" 9 | 10 | //#define SIO_DEBUG 1 //defined only for debug versions using the EE_SIO patch 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include "hdl_rpc.h" 45 | 46 | #include 47 | #include 48 | 49 | #define NEWLIB_PORT_AWARE 50 | #include 51 | #include 52 | 53 | #ifdef SIO_DEBUG 54 | #define DPRINTF(args...) sio_printf(args) 55 | #else 56 | #define DPRINTF(args...) printf(args) 57 | #endif 58 | 59 | #define TRUE 1 60 | #define FALSE 0 61 | 62 | enum { // cnfmode values for getFilePath in browsing for configurable file paths 63 | NON_CNF = 0, // Normal browser mode, not configuration mode 64 | LK_ELF_CNF, // Normal ELF choice for launch keys 65 | USBD_IRX_CNF, // USBD.IRX choice for startup 66 | SKIN_CNF, // Skin JPG choice 67 | GUI_SKIN_CNF, // GUI Skin JPG choice 68 | USBKBD_IRX_CNF, // USB keyboard IRX choice (only PS2SDK) 69 | KBDMAP_FILE_CNF, // USB keyboard mapping table choice 70 | CNF_PATH_CNF, // CNF Path override choice 71 | TEXT_CNF, // No restriction choice 72 | DIR_CNF, // Directory choice 73 | JPG_CNF, // Jpg viewer choice 74 | USBMASS_IRX_CNF, // USB_MASS.IRX choice for startup 75 | LANG_CNF, // Language file choice 76 | FONT_CNF, // Font file choice ( .fnt ) 77 | SAVE_CNF, // Generic Save choice (with or without selected file) 78 | CNFMODE_CNT // Total number of cnfmode values defined 79 | }; 80 | 81 | enum { 82 | SCREEN_MARGIN = 16, 83 | FONT_WIDTH = 8, 84 | FONT_HEIGHT = 16, 85 | LINE_THICKNESS = 3, 86 | 87 | MAX_NAME = 256, 88 | MAX_PART_NAME = 32, 89 | MAX_PATH_PAD = 30, 90 | MAX_PATH = 1025, 91 | MAX_ENTRY = 2048, 92 | MAX_PARTITIONS = 1400, 93 | MAX_MENU_TITLE = 40, 94 | MAX_ELF_TITLE = 72, 95 | MAX_TEXT_LINE = 80 96 | }; 97 | 98 | enum COLOR { 99 | COLOR_BACKGR = 0, 100 | COLOR_FRAME, 101 | COLOR_SELECT, 102 | COLOR_TEXT, 103 | COLOR_GRAPH1, 104 | COLOR_GRAPH2, 105 | COLOR_GRAPH3, 106 | COLOR_GRAPH4, 107 | 108 | COLOR_COUNT 109 | }; 110 | 111 | enum SETTING_LK { 112 | SETTING_LK_AUTO = 0, 113 | SETTING_LK_CIRCLE, 114 | SETTING_LK_CROSS, 115 | SETTING_LK_SQUARE, 116 | SETTING_LK_TRIANGLE, 117 | SETTING_LK_L1, 118 | SETTING_LK_R1, 119 | SETTING_LK_L2, 120 | SETTING_LK_R2, 121 | SETTING_LK_L3, 122 | SETTING_LK_R3, 123 | SETTING_LK_START, 124 | SETTING_LK_SELECT, 125 | SETTING_LK_LEFT, 126 | SETTING_LK_RIGHT, 127 | 128 | SETTING_LK_BTN_COUNT, 129 | 130 | //Special paths 131 | SETTING_LK_ESR = SETTING_LK_BTN_COUNT, 132 | SETTING_LK_OSDSYS, 133 | 134 | SETTING_LK_COUNT 135 | }; 136 | 137 | typedef struct 138 | { 139 | char CNF_Path[MAX_PATH]; 140 | char LK_Path[SETTING_LK_COUNT][MAX_PATH]; 141 | char LK_Title[SETTING_LK_COUNT][MAX_ELF_TITLE]; 142 | int LK_Flag[SETTING_LK_COUNT]; 143 | char Misc[64]; 144 | char Misc_PS2Disc[64]; 145 | char Misc_FileBrowser[64]; 146 | char Misc_PS2Browser[64]; 147 | char Misc_PS2Net[64]; 148 | char Misc_PS2PowerOff[64]; 149 | char Misc_HddManager[64]; 150 | char Misc_TextEditor[64]; 151 | char Misc_JpgViewer[64]; 152 | char Misc_Configure[64]; 153 | char Misc_Load_CNFprev[64]; 154 | char Misc_Load_CNFnext[64]; 155 | char Misc_Set_CNF_Path[64]; 156 | char Misc_Load_CNF[64]; 157 | char Misc_ShowFont[64]; 158 | char Misc_Debug_Info[64]; 159 | char Misc_About_uLE[64]; 160 | char Misc_OSDSYS[64]; 161 | char usbd_file[MAX_PATH]; 162 | char usbkbd_file[MAX_PATH]; 163 | char usbmass_file[MAX_PATH]; 164 | char kbdmap_file[MAX_PATH]; 165 | char skin[MAX_PATH]; 166 | char GUI_skin[MAX_PATH]; 167 | char Menu_Title[MAX_MENU_TITLE + 1]; 168 | char lang_file[MAX_PATH]; 169 | char font_file[MAX_PATH]; 170 | int Menu_Frame; 171 | int Show_Menu; 172 | int timeout; 173 | int Hide_Paths; 174 | u64 color[8]; 175 | int screen_x; 176 | int screen_y; 177 | int numCNF; 178 | int swapKeys; 179 | int Brightness; 180 | int TV_mode; 181 | int Popup_Opaque; 182 | int Init_Delay; 183 | int usbkbd_used; 184 | int Show_Titles; 185 | int PathPad_Lock; 186 | int JpgView_Timer; 187 | int JpgView_Trans; 188 | int JpgView_Full; 189 | int PSU_HugeNames; 190 | int PSU_DateNames; 191 | int PSU_NoOverwrite; 192 | int FB_NoIcons; 193 | } SETTING; 194 | 195 | typedef struct 196 | { 197 | int ip[4]; 198 | int nm[4]; 199 | int gw[4]; 200 | } data_ip_struct; 201 | 202 | extern char LaunchElfDir[MAX_PATH], LastDir[MAX_NAME]; 203 | 204 | /* main.c */ 205 | extern int TV_mode; 206 | extern int swapKeys; 207 | extern int GUI_active; // Skin and Main Skin switch 208 | extern int cdmode; //Last detected disc type 209 | 210 | void load_vmc_fs(void); 211 | void loadHddModules(void); 212 | void loadHdlInfoModule(void); 213 | int uLE_related(char *pathout, const char *pathin); 214 | int uLE_InitializeRegion(void); 215 | int uLE_cdDiscValid(void); 216 | int uLE_cdStop(void); 217 | int IsSupportedFileType(char *path); 218 | 219 | /* elf.c */ 220 | int checkELFheader(char *filename); 221 | void RunLoaderElf(char *filename, char *); 222 | 223 | /* draw.c */ 224 | #define BACKGROUND_PIC 0 225 | #define PREVIEW_PIC 1 226 | #define JPG_PIC 2 227 | #define THUMB_PIC 3 228 | #define PREVIEW_GUI 4 229 | 230 | #define FOLDER 0 231 | #define WARNING 1 232 | 233 | extern unsigned char icon_folder[]; 234 | extern unsigned char icon_warning[]; 235 | 236 | extern GSGLOBAL *gsGlobal; 237 | extern GSTEXTURE TexSkin, TexPreview, TexPicture, TexThumb[MAX_ENTRY], TexIcon[2]; 238 | extern int testskin, testsetskin, testjpg, testthumb; 239 | extern float PicWidth, PicHeight, PicW, PicH, PicCoeff; 240 | extern int SCREEN_WIDTH; 241 | extern int SCREEN_HEIGHT; 242 | extern int Menu_start_x; 243 | extern int Menu_title_y; 244 | extern int Menu_message_y; 245 | extern int Frame_start_y; 246 | extern int Menu_start_y; 247 | extern int Menu_end_y; 248 | extern int Frame_end_y; 249 | extern int Menu_tooltip_y; 250 | extern u64 BrightColor; 251 | extern int PicRotate, FullScreen; 252 | extern u8 FontBuffer[256 * 16]; 253 | 254 | void setScrTmp(const char *msg0, const char *msg1); 255 | void drawSprite(u64 color, int x1, int y1, int x2, int y2); 256 | void drawPopSprite(u64 color, int x1, int y1, int x2, int y2); 257 | void drawOpSprite(u64 color, int x1, int y1, int x2, int y2); 258 | void drawMsg(const char *msg); 259 | void drawLastMsg(void); 260 | void setupGS(void); 261 | void updateScreenMode(void); 262 | void clrScr(u64 color); 263 | void setBrightness(int Brightness); 264 | void loadSkin(int Picture, char *Path, int ThumbNum); 265 | void drawScr(void); 266 | void drawFrame(int x1, int y1, int x2, int y2, u64 color); 267 | void drawChar(unsigned int c, int x, int y, u64 colour); 268 | int printXY(const char *s, int x, int y, u64 colour, int draw, int space); 269 | int printXY_sjis(const unsigned char *s, int x, int y, u64 colour, int); 270 | char *transcpy_sjis(char *d, const unsigned char *s); 271 | void loadIcon(void); 272 | int loadFont(char *path_arg); 273 | //Comment out WriteFont_C when not used (also requires patch in draw.c) 274 | //int WriteFont_C(char *pathname); 275 | 276 | /* pad.c */ 277 | #define PAD_R3_V0 0x010000 278 | #define PAD_R3_V1 0x020000 279 | #define PAD_R3_H0 0x040000 280 | #define PAD_R3_H1 0x080000 281 | #define PAD_L3_V0 0x100000 282 | #define PAD_L3_V1 0x200000 283 | #define PAD_L3_H0 0x400000 284 | #define PAD_L3_H1 0x800000 285 | 286 | extern u32 joy_value; 287 | extern u32 new_pad; 288 | int setupPad(void); 289 | int readpad(void); 290 | int readpad_no_KB(void); 291 | int readpad_noRepeat(void); 292 | void waitPadReady(int port, int slot); 293 | void waitAnyPadReady(void); 294 | 295 | /* config.c */ 296 | enum TV_mode { 297 | TV_mode_AUTO = 0, 298 | TV_mode_NTSC, 299 | TV_mode_PAL, 300 | TV_mode_VGA, 301 | TV_mode_480P, 302 | 303 | TV_mode_COUNT 304 | }; 305 | 306 | extern char PathPad[30][MAX_PATH]; 307 | extern SETTING *setting; 308 | void initConfig(void); 309 | int loadConfig(char *, char *); //0==OK, -1==load failed 310 | void config(char *, char *); 311 | int get_CNF_string(char **CNF_p_p, 312 | char **name_p_p, 313 | char **value_p_p); //main CNF name,value parser 314 | char *preloadCNF(char *path); //loads file into RAM it allocates 315 | 316 | /* filer.c */ 317 | typedef struct 318 | { 319 | char name[MAX_NAME]; 320 | unsigned char title[32 * 2 + 1]; 321 | sceMcTblGetDir stats; 322 | } FILEINFO; 323 | 324 | #define MOUNT_LIMIT 4 325 | extern char mountedParty[MOUNT_LIMIT][MAX_NAME]; 326 | extern int latestMount; 327 | extern int vmcMounted[2]; 328 | extern int vmc_PartyIndex[2]; //PFS index for each VMC, unless -1 329 | extern int Party_vmcIndex[MOUNT_LIMIT]; //VMC index for each PFS, unless -1 330 | extern int nparties; //Clearing this causes FileBrowser to refresh party list 331 | extern unsigned char *elisaFnt; 332 | char *PathPad_menu(const char *path); 333 | int getFilePath(char *out, const int cnfmode); 334 | int ynDialog(const char *message); 335 | void nonDialog(char *message); 336 | int keyboard(char *out, int max); 337 | void genLimObjName(char *uLE_path, int reserve); 338 | int genFixPath(const char *inp_path, char *gen_path); 339 | int genOpen(char *path, int mode); 340 | int genLseek(int fd, int where, int how); 341 | int genRead(int fd, void *buf, int size); 342 | int genWrite(int fd, void *buf, int size); 343 | int genClose(int fd); 344 | int genDopen(char *path); 345 | int genDclose(int fd); 346 | int genRemove(char *path); 347 | int genRmdir(char *path); 348 | int genCmpFileExt(const char *filename, const char *extension); 349 | int mountParty(const char *party); 350 | void unmountParty(int party_ix); 351 | void unmountAll(void); 352 | int setFileList(const char *path, const char *ext, FILEINFO *files, int cnfmode); 353 | /* VFS layer */ 354 | struct vfs_fh *vfsOpen(char *path, int mode); 355 | int vfsLseek(struct vfs_fh *fh, int where, int how); 356 | int vfsRead(struct vfs_fh *fh, void *buf, int size); 357 | int vfsWrite(struct vfs_fh *fh, void *buf, int size); 358 | int vfsClose(struct vfs_fh *fh); 359 | 360 | /* hdd.c */ 361 | void DebugDisp(char *Message); 362 | void hddManager(void); 363 | 364 | /* editor.c */ 365 | void TextEditor(char *path); 366 | 367 | /* timer.c */ 368 | extern u64 WaitTime; 369 | extern u64 CurrTime; 370 | 371 | u64 Timer(void); 372 | 373 | /* jpgviewer.c */ 374 | void JpgViewer(char *file); 375 | 376 | /* lang.c */ 377 | typedef struct Language 378 | { 379 | char *String; 380 | } Language; 381 | 382 | enum { 383 | #define lang(id, name, value) LANG_##name, 384 | #include "lang.h" 385 | #undef lang 386 | LANG_COUNT 387 | }; 388 | 389 | #define LNG(name) Lang_String[LANG_##name].String 390 | #define LNG_DEF(name) Lang_Default[LANG_##name].String 391 | 392 | extern Language Lang_String[]; 393 | extern Language Lang_Default[]; 394 | extern Language *External_Lang_Buffer; 395 | 396 | void Init_Default_Language(void); 397 | void Load_External_Language(void); 398 | 399 | /* font_uLE.c */ 400 | 401 | extern unsigned char font_uLE[]; 402 | enum { 403 | //0x100-0x109 are 5 double width characters for D-Pad buttons, which are accessed as: 404 | //"ÿ0"==Circle "ÿ1"==Cross "ÿ2"==Square "ÿ3"==Triangle "ÿ4"==filled Square 405 | RIGHT_CUR = 0x10A, //Triangle pointing left, for use to the right of an item 406 | LEFT_CUR = 0x10B, //Triangle pointing right, for use to the left of an item 407 | UP_ARROW = 0x10C, //Arrow pointing up 408 | DN_ARROW = 0x10D, //Arrow pointing up 409 | LT_ARROW = 0x10E, //Arrow pointing up 410 | RT_ARROW = 0x10F, //Arrow pointing up 411 | TEXT_CUR = 0x110, //Vertical bar, for use between two text characters 412 | UL_ARROW = 0x111, //Arrow pointing up and to the left, from a vertical start. 413 | BR_SPLIT = 0x112, //Splits rectangle from BL to TR with BR portion filled 414 | BL_SPLIT = 0x113, //Splits rectangle from TL to BR with BL portion filled 415 | //0x114-0x11B are 4 double width characters for D-Pad buttons, which are accessed as: 416 | //"ÿ:"==Right "ÿ;"==Down "ÿ<"==Left "ÿ="==Up 417 | //0x11C-0x123 are 4 doubled characters used as normal/marked folder/file icons 418 | ICON_FOLDER = 0x11C, 419 | ICON_M_FOLDER = 0x11E, 420 | ICON_FILE = 0x120, 421 | ICON_M_FILE = 0x122, 422 | FONT_COUNT = 0x124 //Total number of characters in font 423 | }; 424 | 425 | /* makeicon.c */ 426 | int make_icon(char *icontext, char *filename); 427 | int make_iconsys(char *title, char *iconname, char *filename); 428 | 429 | 430 | //vmcfs definitions 431 | 432 | // The devctl commands: 0x56 == V, 0x4D == M, 0x43 == C, 0x01, 0x02, ... == command number. 433 | #define DEVCTL_VMCFS_CLEAN 0x564D4301 // Set as free all fat cluster corresponding to a none existing object. ( Object are just marked as none existing but not removed from fat table when rmdir or remove fonctions are call. This allow to recover a deleted file. ) 434 | #define DEVCTL_VMCFS_CKFREE 0x564D4302 // Check free space available on vmc. 435 | 436 | // The ioctl commands: 0x56 == V, 0x4D == M, 0x43 == C, 0x01, 0x02, ... == command number. 437 | #define IOCTL_VMCFS_RECOVER 0x564D4303 // Recover an object marked as none existing. ( data must be a valid path to an object in vmc file ) 438 | 439 | // Vmc format enum 440 | typedef enum { 441 | FORMAT_FULL, 442 | FORMAT_FAST 443 | } Vmc_Format_Enum; 444 | 445 | 446 | // chkesr_rpc.c 447 | extern int Check_ESR_Disc(void); 448 | 449 | //USB_mass definitions for multiple drive usage 450 | 451 | #define USB_MASS_MAX_DRIVES 10 452 | 453 | extern char USB_mass_ix[10]; 454 | extern int USB_mass_max_drives; 455 | extern u64 USB_mass_scan_time; 456 | extern int USB_mass_scanned; 457 | extern int USB_mass_loaded; //0==none, 1==internal, 2==external 458 | 459 | #define MC_ATTR_norm_folder 0x8427 //Normal folder on PS2 MC 460 | #define MC_ATTR_prot_folder 0x842F //Protected folder on PS2 MC 461 | #define MC_ATTR_PS1_folder 0x9027 //PS1 save folder on PS2 MC 462 | #define MC_ATTR_norm_file 0x8497 //file (PS2/PS1) on PS2 MC 463 | #define MC_ATTR_PS1_file 0x9417 //PS1 save file on PS1 MC 464 | extern int size_valid; 465 | extern int time_valid; 466 | void clear_mcTable(sceMcTblGetDir *mcT); 467 | 468 | #endif 469 | -------------------------------------------------------------------------------- /nfs.c: -------------------------------------------------------------------------------- 1 | /* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ 2 | //--------------------------------------------------------------------------- 3 | //File name: nfs.c 4 | //--------------------------------------------------------------------------- 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | //#define DEBUG 24 | 25 | #ifdef DEBUG 26 | static int ns = -1; 27 | static char sb[1024]; 28 | #define LOG(...) do { \ 29 | if (ns >= 0) { \ 30 | sprintf(sb, __VA_ARGS__); \ 31 | lwip_write(ns, sb, strlen(sb)); \ 32 | } \ 33 | } while(0); 34 | #else 35 | #define LOG(...) do { } while(0); 36 | #endif 37 | 38 | enum ftype3 { 39 | NF3REG = 1, 40 | NF3DIR = 2, 41 | NF3BLK = 3, 42 | NF3CHR = 4, 43 | NF3LNK = 5, 44 | NF3SOCK = 6, 45 | NF3FIFO = 7, 46 | }; 47 | 48 | struct nfs_share *nfs_shares = NULL; 49 | 50 | static void free_nfs_share(struct nfs_share *nfs_share) 51 | { 52 | if (nfs_share == NULL) { 53 | return; 54 | } 55 | LOG("free_nfs_share(%s)\n", nfs_share->name); 56 | if (nfs_share->nfs) { 57 | nfs_destroy_context(nfs_share->nfs); 58 | } 59 | free(nfs_share->name); 60 | free(nfs_share); 61 | } 62 | 63 | static struct nfs_share *nfs_find_share(const char *name); 64 | 65 | static int loadNFSCNF(char *path) 66 | { 67 | char *RAM_p; 68 | char *CNF_p, *name, *value; 69 | struct nfs_share *nfs_share = NULL; 70 | int entries = 0; 71 | 72 | LOG("try reading config from %s\n", path); 73 | if (!(RAM_p = preloadCNF(path))) 74 | return entries; 75 | CNF_p = RAM_p; 76 | while (get_CNF_string(&CNF_p, &name, &value)) { 77 | if (nfs_share == NULL) { 78 | nfs_share = malloc(sizeof(struct nfs_share)); 79 | memset(nfs_share, 0, sizeof(struct nfs_share)); 80 | } 81 | if (!strcmp(name, "NAME")) { 82 | nfs_share->name = strdup(value); 83 | } else if (!strcmp(name, "URL")) { 84 | struct nfs_context *nfs; 85 | struct nfs_url *url; 86 | 87 | if (nfs_find_share(nfs_share->name)) { 88 | free(nfs_share); 89 | nfs_share = NULL; 90 | continue; 91 | } 92 | nfs_share->url = strdup(value); 93 | nfs_share->nfs = nfs = nfs_init_context(); 94 | url = nfs_parse_url_dir(nfs, nfs_share->url); 95 | if (nfs_mount(nfs, url->server, url->path) < 0) { 96 | scr_printf("failed to connect to : %s:/%s %s\n", 97 | url->server, url->path, 98 | nfs_get_error(nfs)); 99 | nfs_destroy_url(url); 100 | nfs_destroy_context(nfs); 101 | free_nfs_share(nfs_share); 102 | nfs_share = NULL; 103 | continue; 104 | } 105 | scr_printf("Mounted share: %s:%s as %s\n", 106 | url->server, url->path, nfs_share->name); 107 | LOG("Mounted %s:%s as %s\n",url->server, url->path, nfs_share->name); 108 | nfs_destroy_url(url); 109 | 110 | nfs_share->next = nfs_shares; 111 | nfs_shares = nfs_share; 112 | nfs_share = NULL; 113 | entries++; 114 | } 115 | } 116 | free(RAM_p); 117 | return entries; 118 | } 119 | 120 | void deinit_nfs(void) 121 | { 122 | struct nfs_share *nfs_share; 123 | 124 | while (nfs_shares) { 125 | nfs_share = nfs_shares->next; 126 | free_nfs_share(nfs_shares); 127 | nfs_shares = nfs_share; 128 | } 129 | LOG("stopped logging to socket...\n"); 130 | } 131 | 132 | int init_nfs(const char *ip, const char *netmask, const char *gw) 133 | { 134 | int rc; 135 | 136 | scr_printf("Starting NFS\n"); 137 | 138 | #ifdef DEBUG 139 | ns = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 140 | if (ns >= 0) { 141 | struct sockaddr_in sin4; 142 | sin4.sin_addr.s_addr = inet_addr("10.10.10.11"); 143 | sin4.sin_family = AF_INET; 144 | sin4.sin_port = htons(9999); 145 | if (connect(ns, (struct sockaddr *)&sin4, sizeof(sin4)) < 0) { 146 | close(ns); 147 | ns = -1; 148 | } 149 | LOG("started logging to socket...\n"); 150 | } 151 | #endif 152 | 153 | rc = loadNFSCNF("mc0:/SYS-CONF/NFS.CNF"); 154 | if (!rc) { 155 | rc = loadNFSCNF("mc1:/SYS-CONF/NFS.CNF"); 156 | } 157 | if (!rc) { 158 | rc = loadNFSCNF("mass:/SYS-CONF/NFS.CNF"); 159 | } 160 | scr_printf("init_nfs.\n"); 161 | 162 | return 0; 163 | } 164 | 165 | static struct nfs_share *nfs_find_share(const char *name) 166 | { 167 | struct nfs_share *share; 168 | 169 | LOG("nfs_find_share(%s)\n", name); 170 | for (share = nfs_shares; share; share = share->next) { 171 | if (!strcmp(share->name, name)) { 172 | return share; 173 | } 174 | } 175 | 176 | LOG("share not found\n"); 177 | return NULL; 178 | } 179 | 180 | static void set_time(sceMcStDateTime *ps2time, u64 nfstime) 181 | { 182 | struct tm *tm; 183 | time_t t = nfstime & 0xffffffff; 184 | 185 | tm = localtime(&t); 186 | if (tm == NULL) { 187 | return; 188 | } 189 | ps2time->Sec = tm->tm_sec; 190 | ps2time->Min = tm->tm_min; 191 | ps2time->Hour = tm->tm_hour; 192 | ps2time->Day = tm->tm_mday + 1; 193 | ps2time->Month = tm->tm_mon + 1; 194 | ps2time->Year = tm->tm_year + 1900; 195 | } 196 | 197 | static void find_share(const char *path, char **name, char **p, 198 | struct nfs_share **share) 199 | { 200 | LOG("find_share(%s)\n", path); 201 | *name = strdup(&path[5]); 202 | if (*name == NULL) { 203 | return; 204 | } 205 | *p = strchr(*name, '/'); 206 | if (*p == NULL) { 207 | return; 208 | } 209 | *((*p)++) = 0; 210 | 211 | *share = nfs_find_share(*name); 212 | if (*share == NULL) { 213 | return; 214 | } 215 | } 216 | 217 | int readNFS(const char *path, FILEINFO *info, int max) 218 | { 219 | int n = 0; 220 | struct nfsdir *dir = NULL; 221 | struct nfs_share *share = NULL; 222 | char *name = NULL, *p; 223 | struct nfsdirent *ent; 224 | 225 | LOG("readNFS(%s)\n", path); 226 | /* Root of nfs: is a list of all the named shares */ 227 | if (path[5] == '\0') { 228 | for (share = nfs_shares; share; share = share->next) { 229 | if (strlen(share->name) >= MAX_NAME) { 230 | continue; 231 | } 232 | strncpy(info[n].name, share->name, MAX_NAME-1); 233 | info[n].name[MAX_NAME-1] = 0; 234 | clear_mcTable(&info[n].stats); 235 | info[n].stats.AttrFile = MC_ATTR_norm_folder; 236 | strncpy((char *)info[n].stats.EntryName, info[n].name, 32); 237 | n++; 238 | if (n >= max) { 239 | break; 240 | } 241 | } 242 | goto finished; 243 | } 244 | 245 | /* Find the share */ 246 | LOG("not root, check %s\n", path); 247 | find_share(path, &name, &p, &share); 248 | if (share == NULL) { 249 | goto finished; 250 | } 251 | 252 | nfs_opendir(share->nfs, p, &dir); 253 | if (dir == NULL) { 254 | LOG("nfs_opendir_failed with %s\n", nfs_get_error(share->nfs)); 255 | goto finished; 256 | } 257 | LOG("nfs_opendir success\n"); 258 | while ((ent = nfs_readdir(share->nfs, dir))) { 259 | if (!strcmp(ent->name, ".") || !strcmp(ent->name, "..")) { 260 | continue; 261 | } 262 | if (ent->type != NF3REG && 263 | ent->type != NF3DIR) { 264 | continue; 265 | } 266 | if (strlen(ent->name) >= MAX_NAME) { 267 | continue; 268 | } 269 | strncpy(info[n].name, ent->name, MAX_NAME); 270 | info[n].name[MAX_NAME-1] = 0; 271 | clear_mcTable(&info[n].stats); 272 | if (ent->type == NF3DIR) { 273 | info[n].stats.AttrFile = MC_ATTR_norm_folder; 274 | } else { 275 | info[n].stats.AttrFile = MC_ATTR_norm_file; 276 | info[n].stats.FileSizeByte = ent->size; 277 | info[n].stats.Reserve2 = 0; 278 | } 279 | 280 | strncpy((char *)info[n].stats.EntryName, info[n].name, 32); 281 | set_time(&info[n].stats._Create, ent->ctime.tv_sec); 282 | set_time(&info[n].stats._Modify, ent->mtime.tv_sec); 283 | n++; 284 | if (n >= max) 285 | break; 286 | } 287 | size_valid = 1; 288 | time_valid = 1; 289 | 290 | finished: 291 | free(name); 292 | if (dir) { 293 | nfs_closedir(share->nfs, dir); 294 | } 295 | LOG("returned %d entries\n", n); 296 | return n; 297 | } 298 | 299 | int NFSmkdir(const char *path, int fileMode) 300 | { 301 | struct nfs_share *share = NULL; 302 | char *name = NULL, *p = NULL; 303 | int rc = 0; 304 | 305 | LOG("NFSmkdir [%s]\n", path); 306 | if (path[5] == '\0') { 307 | return -EINVAL; 308 | } 309 | 310 | find_share(path, &name, &p, &share); 311 | if (share == NULL) { 312 | free(name); 313 | return -EINVAL; 314 | } 315 | 316 | rc = nfs_mkdir(share->nfs, p); 317 | if (rc) { 318 | goto finished; 319 | } 320 | 321 | finished: 322 | free(name); 323 | return rc; 324 | } 325 | 326 | int NFSrmdir(const char *path) 327 | { 328 | struct nfs_share *share = NULL; 329 | char *name = NULL, *p = NULL; 330 | int rc = 0; 331 | 332 | LOG("NFSrmdir\n"); 333 | if (path[5] == '\0') { 334 | return -EINVAL; 335 | } 336 | 337 | find_share(path, &name, &p, &share); 338 | if (share == NULL) { 339 | free(name); 340 | return -EINVAL; 341 | } 342 | 343 | if (p[strlen(p) - 1] == '/') { 344 | p[strlen(p) - 1] = 0; 345 | } 346 | rc = nfs_rmdir(share->nfs, p); 347 | if (rc) { 348 | goto finished; 349 | } 350 | 351 | finished: 352 | free(name); 353 | return rc; 354 | } 355 | 356 | int NFSunlink(const char *path) 357 | { 358 | struct nfs_share *share = NULL; 359 | char *name = NULL, *p = NULL; 360 | int rc = 0; 361 | 362 | LOG("NFSunlink\n"); 363 | if (path[5] == '\0') { 364 | return -EINVAL; 365 | } 366 | 367 | find_share(path, &name, &p, &share); 368 | if (share == NULL) { 369 | free(name); 370 | return -EINVAL; 371 | } 372 | 373 | rc = nfs_unlink(share->nfs, p); 374 | if (rc) { 375 | goto finished; 376 | } 377 | 378 | finished: 379 | free(name); 380 | return rc; 381 | } 382 | 383 | struct NFSFH *NFSopen(const char *path, int mode) 384 | { 385 | struct nfs_share *share = NULL; 386 | char *name = NULL, *p = NULL; 387 | struct NFSFH *fh; 388 | 389 | LOG("NFSopen %s\n", path); 390 | if (path[5] == '\0') { 391 | return NULL; 392 | } 393 | 394 | find_share(path, &name, &p, &share); 395 | if (share == NULL) { 396 | free(name); 397 | return NULL; 398 | } 399 | fh = malloc(sizeof(struct NFSFH)); 400 | if (fh == NULL) { 401 | free(name); 402 | return NULL; 403 | } 404 | 405 | fh->nfs = share->nfs; 406 | LOG("nfs_open [%s]\n", p); 407 | nfs_open(share->nfs, p, mode, &fh->fh); 408 | free(name); 409 | if(fh->fh == NULL) { 410 | free(fh); 411 | return NULL; 412 | } 413 | return fh; 414 | } 415 | 416 | int NFSclose(struct NFSFH *fh) 417 | { 418 | LOG("NFSclose\n"); 419 | return nfs_close(fh->nfs, fh->fh); 420 | } 421 | 422 | int NFSread(struct NFSFH *fh, char *buf, int size) 423 | { 424 | LOG("NFSread\n"); 425 | return nfs_read(fh->nfs, fh->fh, size, buf); 426 | } 427 | 428 | int NFSwrite(struct NFSFH *fh, char *buf, int size) 429 | { 430 | LOG("NFSwrite\n"); 431 | return nfs_write(fh->nfs, fh->fh, size, buf); 432 | } 433 | 434 | int NFSlseek(struct NFSFH *fh, int where, int how) 435 | { 436 | int rc; 437 | uint64_t co = 0; 438 | 439 | LOG("NFSlseek %d %d\n", where, how); 440 | rc = nfs_lseek(fh->nfs, fh->fh, where, how, &co); 441 | if (rc < 0) { 442 | return -EIO; 443 | } 444 | LOG("rc:%d %s\n", rc, nfs_get_error(fh->nfs)); 445 | return co; 446 | } 447 | 448 | int NFSrename(const char *path, const char *newpath) 449 | { 450 | struct nfs_share *share = NULL; 451 | char *name = NULL, *p = NULL; 452 | int ret; 453 | 454 | LOG("NFSrename\n"); 455 | if (path[5] == '\0') { 456 | return -EINVAL; 457 | } 458 | 459 | find_share(path, &name, &p, &share); 460 | if (share == NULL) { 461 | free(name); 462 | return -ENOENT; 463 | } 464 | 465 | ret = nfs_rename(share->nfs, p, newpath); 466 | free(name); 467 | 468 | return ret; 469 | } 470 | 471 | //--------------------------------------------------------------------------- 472 | //End of file: nfs.c 473 | //--------------------------------------------------------------------------- 474 | -------------------------------------------------------------------------------- /smb2.c: -------------------------------------------------------------------------------- 1 | /* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */ 2 | //--------------------------------------------------------------------------- 3 | //File name: smb2.c 4 | //--------------------------------------------------------------------------- 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | struct smb2_share *smb2_shares = NULL; 23 | 24 | #define discard_const(ptr) ((void *)((intptr_t)(ptr))) 25 | 26 | static struct smb2_share *smb2_find_share(const char *name); 27 | 28 | static void EthStatusCheckCb(s32 alarm_id, u16 time, void *common) 29 | { 30 | iWakeupThread(*(int*)common); 31 | } 32 | 33 | static int WaitValidNetState(int (*checkingFunction)(void)) 34 | { 35 | int ThreadID, retry_cycles; 36 | 37 | // Wait for a valid network status; 38 | ThreadID = GetThreadId(); 39 | for(retry_cycles = 0; checkingFunction() == 0; retry_cycles++) 40 | { //Sleep for 1000ms. 41 | SetAlarm(1000 * 16, &EthStatusCheckCb, &ThreadID); 42 | SleepThread(); 43 | 44 | if(retry_cycles >= 10) //10s = 10*1000ms 45 | return -1; 46 | } 47 | 48 | return 0; 49 | } 50 | 51 | static int ethGetNetIFLinkStatus(void) 52 | { 53 | return(NetManIoctl(NETMAN_NETIF_IOCTL_GET_LINK_STATUS, NULL, 0, NULL, 0) == NETMAN_NETIF_ETH_LINK_STATE_UP); 54 | } 55 | 56 | static int ethWaitValidNetIFLinkState(void) 57 | { 58 | return WaitValidNetState(ðGetNetIFLinkStatus); 59 | } 60 | 61 | static void free_smb2_share(struct smb2_share *smb2_share) 62 | { 63 | if (smb2_share == NULL) { 64 | return; 65 | } 66 | if (smb2_share->smb2) { 67 | smb2_disconnect_share(smb2_share->smb2); 68 | smb2_destroy_context(smb2_share->smb2); 69 | } 70 | free(smb2_share->name); 71 | free(discard_const(smb2_share->user)); 72 | free(discard_const(smb2_share->password)); 73 | free(smb2_share); 74 | } 75 | 76 | static int loadSMB2CNF(char *path) 77 | { 78 | char *RAM_p; 79 | char *CNF_p, *name, *value; 80 | struct smb2_share *smb2_share = NULL; 81 | int entries = 0; 82 | 83 | if (!(RAM_p = preloadCNF(path))) 84 | return entries; 85 | CNF_p = RAM_p; 86 | while (get_CNF_string(&CNF_p, &name, &value)) { 87 | if (smb2_share == NULL) { 88 | smb2_share = malloc(sizeof(struct smb2_share)); 89 | memset(smb2_share, 0, sizeof(struct smb2_share)); 90 | } 91 | if (!strcmp(name, "NAME")) { 92 | smb2_share->name = strdup(value); 93 | } else if (!strcmp(name, "USERNAME")) { 94 | smb2_share->user = strdup(value); 95 | } else if (!strcmp(name, "PASSWORD")) { 96 | smb2_share->password = strdup(value); 97 | } else if (!strcmp(name, "URL")) { 98 | struct smb2_context *smb2; 99 | struct smb2_url *url; 100 | 101 | if (smb2_find_share(smb2_share->name)) { 102 | free(smb2_share); 103 | smb2_share = NULL; 104 | continue; 105 | } 106 | smb2_share->url = strdup(value); 107 | smb2_share->smb2 = smb2 = smb2_init_context(); 108 | smb2_set_user(smb2, smb2_share->user); 109 | smb2_set_password(smb2, smb2_share->password); 110 | url = smb2_parse_url(smb2, smb2_share->url); 111 | if (smb2_connect_share(smb2, url->server, url->share, 112 | smb2_share->user) < 0) { 113 | scr_printf("failed to connect to : //%s/%s %s\n", 114 | url->server, url->share, 115 | smb2_get_error(smb2)); 116 | free(smb2_share); 117 | smb2_share = NULL; 118 | continue; 119 | } 120 | scr_printf("Mounted share: \\\\%s\\%s as %s\n", 121 | url->server, url->share, smb2_share->name); 122 | smb2_destroy_url(url); 123 | 124 | smb2_share->next = smb2_shares; 125 | smb2_shares = smb2_share; 126 | smb2_share = NULL; 127 | entries++; 128 | } 129 | } 130 | free(RAM_p); 131 | return entries; 132 | } 133 | 134 | void deinit_smb2(void) 135 | { 136 | struct smb2_share *smb2_share; 137 | 138 | while (smb2_shares) { 139 | smb2_share = smb2_shares->next; 140 | free_smb2_share(smb2_shares); 141 | smb2_shares = smb2_share; 142 | } 143 | } 144 | 145 | int init_smb2(const char *ip, const char *netmask, const char *gw) 146 | { 147 | struct ip4_addr IP, NM, GW; 148 | int ip4[4]; 149 | int rc; 150 | 151 | init_scr(); 152 | {int ii; for (ii=0;ii<2;ii++)scr_printf("Woff\n");} 153 | 154 | NetManInit(); 155 | 156 | sscanf(ip, "%d.%d.%d.%d", &ip4[0], &ip4[1], &ip4[2], &ip4[3]); 157 | IP4_ADDR(&IP, ip4[0], ip4[1], ip4[2], ip4[3]); 158 | sscanf(netmask, "%d.%d.%d.%d", &ip4[0], &ip4[1], &ip4[2], &ip4[3]); 159 | IP4_ADDR(&NM, ip4[0], ip4[1], ip4[2], ip4[3]); 160 | sscanf(gw, "%d.%d.%d.%d", &ip4[0], &ip4[1], &ip4[2], &ip4[3]); 161 | IP4_ADDR(&GW, ip4[0], ip4[1], ip4[2], ip4[3]); 162 | ps2ipInit(&IP, &NM, &GW); 163 | 164 | scr_printf("Waiting for connection...\n"); 165 | if(ethWaitValidNetIFLinkState() != 0) { 166 | scr_printf("Error: failed to get valid link status.\n"); 167 | return -1; 168 | } 169 | scr_printf("Network Initialized\n"); 170 | 171 | rc = loadSMB2CNF("mc0:/SYS-CONF/SMB2.CNF"); 172 | if (!rc) { 173 | rc = loadSMB2CNF("mc1:/SYS-CONF/SMB2.CNF"); 174 | } 175 | if (!rc) { 176 | rc = loadSMB2CNF("mass:/SYS-CONF/SMB2.CNF"); 177 | } 178 | scr_printf("init_smb2.\n"); 179 | 180 | return 0; 181 | } 182 | 183 | static struct smb2_share *smb2_find_share(const char *name) 184 | { 185 | struct smb2_share *share; 186 | 187 | for (share = smb2_shares; share; share = share->next) { 188 | if (!strcmp(share->name, name)) { 189 | return share; 190 | } 191 | } 192 | 193 | return NULL; 194 | } 195 | 196 | static void set_time(sceMcStDateTime *ps2time, u64 smb2time) 197 | { 198 | struct tm *tm; 199 | time_t t = smb2time & 0xffffffff; 200 | 201 | tm = localtime(&t); 202 | if (tm == NULL) { 203 | return; 204 | } 205 | ps2time->Sec = tm->tm_sec; 206 | ps2time->Min = tm->tm_min; 207 | ps2time->Hour = tm->tm_hour; 208 | ps2time->Day = tm->tm_mday + 1; 209 | ps2time->Month = tm->tm_mon + 1; 210 | ps2time->Year = tm->tm_year + 1900; 211 | } 212 | 213 | static void find_share(const char *path, char **name, char **p, 214 | struct smb2_share **share) 215 | { 216 | *name = strdup(&path[6]); 217 | if (*name == NULL) { 218 | return; 219 | } 220 | *p = strchr(*name, '/'); 221 | if (*p == NULL) { 222 | return; 223 | } 224 | *((*p)++) = 0; 225 | 226 | *share = smb2_find_share(*name); 227 | if (*share == NULL) { 228 | return; 229 | } 230 | } 231 | 232 | int readSMB2(const char *path, FILEINFO *info, int max) 233 | { 234 | int n = 0; 235 | struct smb2dir *dir = NULL; 236 | struct smb2_share *share = NULL; 237 | char *name = NULL, *p; 238 | struct smb2dirent *ent; 239 | 240 | /* Root of smb2: is a list of all the named shares */ 241 | if (path[6] == '\0') { 242 | for (share = smb2_shares; share; share = share->next) { 243 | if (strlen(share->name) >= MAX_NAME) { 244 | continue; 245 | } 246 | strncpy(info[n].name, share->name, MAX_NAME-1); 247 | info[n].name[MAX_NAME-1] = 0; 248 | clear_mcTable(&info[n].stats); 249 | info[n].stats.AttrFile = MC_ATTR_norm_folder; 250 | strncpy((char *)info[n].stats.EntryName, info[n].name, 32); 251 | n++; 252 | if (n >= max) { 253 | break; 254 | } 255 | } 256 | goto finished; 257 | } 258 | 259 | /* Find the share */ 260 | find_share(path, &name, &p, &share); 261 | if (share == NULL) { 262 | goto finished; 263 | } 264 | 265 | dir = smb2_opendir(share->smb2, p); 266 | if (dir == NULL) { 267 | goto finished; 268 | } 269 | while ((ent = smb2_readdir(share->smb2, dir))) { 270 | if (!strcmp(ent->name, ".") || !strcmp(ent->name, "..")) { 271 | continue; 272 | } 273 | if (ent->st.smb2_type != SMB2_TYPE_FILE && 274 | ent->st.smb2_type != SMB2_TYPE_DIRECTORY) { 275 | continue; 276 | } 277 | if (strlen(ent->name) >= MAX_NAME) { 278 | continue; 279 | } 280 | strncpy(info[n].name, ent->name, MAX_NAME); 281 | info[n].name[MAX_NAME-1] = 0; 282 | clear_mcTable(&info[n].stats); 283 | if (ent->st.smb2_type == SMB2_TYPE_DIRECTORY) { 284 | info[n].stats.AttrFile = MC_ATTR_norm_folder; 285 | } else { 286 | info[n].stats.AttrFile = MC_ATTR_norm_file; 287 | info[n].stats.FileSizeByte = ent->st.smb2_size; 288 | info[n].stats.Reserve2 = 0; 289 | } 290 | 291 | strncpy((char *)info[n].stats.EntryName, info[n].name, 32); 292 | set_time(&info[n].stats._Create, ent->st.smb2_ctime); 293 | set_time(&info[n].stats._Modify, ent->st.smb2_mtime); 294 | n++; 295 | if (n >= max) 296 | break; 297 | } 298 | size_valid = 1; 299 | time_valid = 1; 300 | 301 | finished: 302 | free(name); 303 | if (dir) { 304 | smb2_closedir(share->smb2, dir); 305 | } 306 | return n; 307 | } 308 | 309 | int SMB2mkdir(const char *path, int fileMode) 310 | { 311 | struct smb2_share *share = NULL; 312 | char *name = NULL, *p = NULL; 313 | int rc = 0; 314 | 315 | if (path[6] == '\0') { 316 | return -EINVAL; 317 | } 318 | 319 | find_share(path, &name, &p, &share); 320 | if (share == NULL) { 321 | free(name); 322 | return -EINVAL; 323 | } 324 | 325 | rc = smb2_mkdir(share->smb2, p); 326 | if (rc) { 327 | goto finished; 328 | } 329 | 330 | finished: 331 | free(name); 332 | return rc; 333 | } 334 | 335 | int SMB2rmdir(const char *path) 336 | { 337 | struct smb2_share *share = NULL; 338 | char *name = NULL, *p = NULL; 339 | int rc = 0; 340 | 341 | if (path[6] == '\0') { 342 | return -EINVAL; 343 | } 344 | 345 | find_share(path, &name, &p, &share); 346 | if (share == NULL) { 347 | free(name); 348 | return -EINVAL; 349 | } 350 | 351 | if (p[strlen(p) - 1] == '/') { 352 | p[strlen(p) - 1] = 0; 353 | } 354 | rc = smb2_rmdir(share->smb2, p); 355 | if (rc) { 356 | goto finished; 357 | } 358 | 359 | finished: 360 | free(name); 361 | return rc; 362 | } 363 | 364 | int SMB2unlink(const char *path) 365 | { 366 | struct smb2_share *share = NULL; 367 | char *name = NULL, *p = NULL; 368 | int rc = 0; 369 | 370 | if (path[6] == '\0') { 371 | return -EINVAL; 372 | } 373 | 374 | find_share(path, &name, &p, &share); 375 | if (share == NULL) { 376 | free(name); 377 | return -EINVAL; 378 | } 379 | 380 | rc = smb2_unlink(share->smb2, p); 381 | if (rc) { 382 | goto finished; 383 | } 384 | 385 | finished: 386 | free(name); 387 | return rc; 388 | } 389 | 390 | struct SMB2FH *SMB2open(const char *path, int mode) 391 | { 392 | struct smb2_share *share = NULL; 393 | char *name = NULL, *p = NULL; 394 | struct SMB2FH *fh; 395 | 396 | if (path[6] == '\0') { 397 | return NULL; 398 | } 399 | 400 | find_share(path, &name, &p, &share); 401 | if (share == NULL) { 402 | free(name); 403 | return NULL; 404 | } 405 | fh = malloc(sizeof(struct SMB2FH)); 406 | if (fh == NULL) { 407 | free(name); 408 | return NULL; 409 | } 410 | 411 | fh->smb2 = share->smb2; 412 | fh->fh = smb2_open(share->smb2, p, mode); 413 | free(name); 414 | if(fh->fh == NULL) { 415 | free(fh); 416 | return NULL; 417 | } 418 | return fh; 419 | } 420 | 421 | int SMB2close(struct SMB2FH *fh) 422 | { 423 | return smb2_close(fh->smb2, fh->fh); 424 | } 425 | 426 | int SMB2read(struct SMB2FH *fh, char *buf, int size) 427 | { 428 | return smb2_read(fh->smb2, fh->fh, (uint8_t *)buf, size); 429 | } 430 | 431 | int SMB2write(struct SMB2FH *fh, char *buf, int size) 432 | { 433 | return smb2_write(fh->smb2, fh->fh, (uint8_t *)buf, size); 434 | } 435 | 436 | int SMB2lseek(struct SMB2FH *fh, int where, int how) 437 | { 438 | return smb2_lseek(fh->smb2, fh->fh, where, how, NULL); 439 | } 440 | 441 | int SMB2rename(const char *path, const char *newpath) 442 | { 443 | struct smb2_share *share = NULL; 444 | char *name = NULL, *p = NULL; 445 | int ret; 446 | 447 | if (path[6] == '\0') { 448 | return -EINVAL; 449 | } 450 | 451 | find_share(path, &name, &p, &share); 452 | if (share == NULL) { 453 | free(name); 454 | return -ENOENT; 455 | } 456 | 457 | ret = smb2_rename(share->smb2, p, newpath); 458 | free(name); 459 | 460 | return ret; 461 | } 462 | 463 | //--------------------------------------------------------------------------- 464 | //End of file: smb2.c 465 | //--------------------------------------------------------------------------- 466 | -------------------------------------------------------------------------------- /makeicon.c: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------- 2 | //File name: makeicon.c 3 | //-------------------------------------------------------------- 4 | #include "launchelf.h" 5 | #include "libmc.h" 6 | #include "math.h" 7 | extern u8 font_uLE[]; 8 | 9 | static u16 *tex_buffer; 10 | 11 | #define ICON_WIDTH 128 12 | #define ICON_HEIGHT 128 13 | #define ICON_MARGIN 0 14 | #define FONT_WIDTH 8 15 | #define FONT_HEIGHT 16 16 | 17 | //f16 = s16/4096 18 | #define f16 s16 19 | #define f32 float 20 | //-------------------------------------------------------------- 21 | struct icon_header 22 | { 23 | u32 icon_id; // PS2 icon id = 0x010000 24 | u32 anim_shapes; // number of animation shapes 25 | u32 texture_type; // 0x07=uncompressed 26 | u32 UNKNOWN; // always 0x3F800000 27 | u32 num_vertices; // always multiple of 3 28 | }; 29 | //-------------------------------------------------------------- 30 | struct icon_vertex 31 | { 32 | f16 xyz[3]; 33 | u16 w; //no idea what this is //RA: but it is required, though it may be zeroed 34 | }; 35 | //-------------------------------------------------------------- 36 | struct icon_texturedata 37 | { 38 | f16 uv[2]; 39 | u8 rgba[4]; 40 | }; 41 | //-------------------------------------------------------------- 42 | struct icon_animheader 43 | { 44 | u32 id; //always 0x01 45 | u32 frame_length; 46 | f32 anim_speed; 47 | u32 play_offset; 48 | u32 num_frames; 49 | }; 50 | //-------------------------------------------------------------- 51 | struct icon_framedata 52 | { 53 | u32 shapeid; 54 | u32 num_keys; 55 | u32 time; 56 | u32 value; 57 | }; 58 | //-------------------------------------------------------------- 59 | // A few cheap defines for assigning vector and texture coordinates to vertices 60 | //Set vector coordinate value of a vertex 61 | #define set_vv(coord, x, y, z) \ 62 | coord.xyz[0] = 4096 * x; \ 63 | coord.xyz[1] = 4096 * y; \ 64 | coord.xyz[2] = 4096 * z; \ 65 | coord.w = 0; 66 | //-------------------------------------------------------------- 67 | // Set texture coordinate value of a vertex 68 | #define set_tv(uv, u, v) \ 69 | uv[0] = u * 4096; \ 70 | uv[1] = v * 4096; 71 | //-------------------------------------------------------------- 72 | // draw a char using the system font (16x16) 73 | void tex_drawChar(unsigned int c, int x, int y, u16 colour) 74 | { 75 | int i, j, k, pixBase, pixMask; 76 | u8 *cm; 77 | 78 | u16 temp_image[16][32]; 79 | // blank out the memory(was causing issues before) 80 | for (i = 0; i < 16; i++) 81 | for (j = 0; j < 32; j++) 82 | temp_image[i][j] = 0x0000; 83 | 84 | if (c >= 0x11A) 85 | c = '_'; 86 | cm = &font_uLE[c * 16]; //cm points to the character definition in the font 87 | 88 | pixMask = 0x80; 89 | for (i = 0; i < 8; i++) { //for i == each pixel column 90 | pixBase = -1; 91 | for (j = 0; j < 16; j++) { //for j == each pixel row 92 | if ((pixBase < 0) && (cm[j] & pixMask)) { //if start of sequence 93 | pixBase = j; 94 | } else if ((pixBase > -1) && !(cm[j] & pixMask)) { //if end of sequence 95 | for (k = pixBase; k < j; k++) 96 | temp_image[i * 2][k * 2] = 0xFFFF; //every other pixel is blank 97 | pixBase = -1; 98 | } 99 | } //ends for j == each pixel row 100 | if (pixBase > -1) //if end of sequence including final row 101 | { 102 | for (k = pixBase; k < j; k++) 103 | temp_image[i * 2][k * 2] = 0xFFFF; 104 | } 105 | pixMask >>= 1; 106 | } //ends for i == each pixel column 107 | 108 | // OR's with the previous bit in the row to fill in the blank space 109 | for (i = 1; i < 16; i += 2) 110 | for (j = 0; j < 32; j++) 111 | temp_image[i][j] = temp_image[i - 1][j] | temp_image[i][j]; 112 | 113 | // OR's with the previous bit in the column to fill in the blank space 114 | for (j = 1; j < 32; j += 2) 115 | for (i = 0; i < 16; i++) 116 | temp_image[i][j] = temp_image[i][j - 1] | temp_image[i][j]; 117 | 118 | //store the temp image buffer into the real image buffer 119 | for (i = 0; i < 16; i++) 120 | for (j = 0; j < 32; j++) 121 | tex_buffer[x + i + (y + j) * 128] = temp_image[i][j]; 122 | } 123 | //-------------------------------------------------------------- 124 | // draw a string of characters to an icon texture, without shift-JIS support 125 | // NOTE: I added in the ability for \n to be part of the string, don't know if its 126 | // necessary though, although there are some cases where it doesnt work 127 | 128 | int tex_printXY(const unsigned char *s, int x, int y, u16 colour) 129 | { 130 | unsigned int c1, c2; 131 | int i; 132 | int text_spacing = 16; //we magnified font 133 | int x_orig = x; 134 | int x_max = x; 135 | i = 0; 136 | while ((c1 = s[i++]) != 0) { 137 | if (c1 == '\t') { //'Horizontal Tab' code ? 138 | x += FONT_WIDTH; //use HT to step half a char space, for centering odd chars 139 | continue; //loop back to try next character 140 | } 141 | if (c1 == '\v') //'Vertical Tab' code ? 142 | goto force_halfrow; //use VT to step half a row down, for centering odd rows 143 | if (c1 == '\r') { //'Carriage Return' code ? 144 | force_newrow: //use CR to step a full row down, and restart a row 145 | y += FONT_HEIGHT; 146 | force_halfrow: //This label is used to allow centering of odd rows 147 | y += FONT_HEIGHT; 148 | if (x > x_max) 149 | x_max = x; 150 | x = x_orig; 151 | continue; //loop back to try next character 152 | } 153 | if (y > ICON_HEIGHT - 2 * FONT_HEIGHT) //if insufficient room for current row 154 | break; //then cut the string rendering here 155 | if (x > ICON_WIDTH - ICON_MARGIN - 2 * FONT_WIDTH) { //if out of room on current row 156 | i--; //back index to retry on next loop 157 | goto force_newrow; //and cut this row here. 158 | } 159 | //Here we know there is room for at least one char on current row 160 | if (c1 != 0xFF) { // Normal character 161 | norm_char: 162 | tex_drawChar(c1, x, y, colour); 163 | x += text_spacing; 164 | continue; 165 | } //End if for normal character 166 | // Here we got a sequence starting with 0xFF ('�') 167 | if ((c2 = s[i++]) == 0) { //if that was the final character 168 | i--; //back index to retry on next loop 169 | goto norm_char; //and go display '�' as any other character 170 | } 171 | //Here we deal with any sequence prefixed by '�' 172 | if ((c2 < '0') || (c2 > '=')) //if the sequence is illegal 173 | continue; //then just ignore it 174 | c1 = (c2 - '0') * 2 + 0x100; //generate adjusted char code > 0xFF 175 | tex_drawChar(c1, x, y, colour); //render this base character to texture 176 | x += text_spacing; 177 | if ((c2 > '4') && (c2 < ':')) //if this is a normal-width character 178 | continue; //continue with the next loop 179 | //compound sequence '�0'=Circle '�1'=Cross '�2'=Square '�3'=Triangle 180 | //'�4'=FilledBox '�:'=Pad_Rt '�;'=Pad_Dn '�<'=Pad_Lt '�='=Pad_Up 181 | if (x > ICON_WIDTH - ICON_MARGIN - 2 * FONT_WIDTH) //if out of room for compound character ? 182 | goto force_newrow; //then cut this row here. 183 | tex_drawChar(c1 + 1, x, y, colour); //render 2nd half of compound character 184 | x += text_spacing; 185 | } // ends while(1) 186 | if (x > x_max) 187 | x_max = x; 188 | return x_max; //Return max X position reached (not needed for anything though) 189 | } 190 | 191 | //-------------------------------------------------------------- 192 | //This is a quick and dirty RLE compression algorithm that assumes 193 | //everything is part of a run, and treats everything as a run, 194 | //regardless as to how long that run is. It could be slightly 195 | //optimized, but the gains would be rather insignifigant. 196 | //NB: With the text magnification used, the assumption of each 197 | //sequence being a run longer than one pixel is always true. 198 | //-------------------------------------------------------------- 199 | u32 tex_compresRLE() 200 | { 201 | u16 *new_tex = (u16 *)malloc(128 * 128 * 2); 202 | u16 outbufferpos = 0, runcounter = 0, currentposition = 0; 203 | while (currentposition < 128 * 128) { 204 | runcounter = 1; 205 | // 16384 is size of the uncompressed texture/2 206 | while (currentposition + runcounter < 16384 && tex_buffer[currentposition] == tex_buffer[currentposition + runcounter]) 207 | runcounter++; 208 | new_tex[outbufferpos++] = runcounter; 209 | new_tex[outbufferpos++] = tex_buffer[currentposition]; 210 | currentposition += runcounter; 211 | } 212 | 213 | u32 size = outbufferpos * 2; 214 | free(tex_buffer); 215 | tex_buffer = (u16 *)malloc(size); 216 | memcpy(tex_buffer, new_tex, size); 217 | free(new_tex); 218 | return size; 219 | } 220 | //-------------------------------------------------------------- 221 | //These defines multiplied like '4096*+xs' yield a standard sized flat icon 222 | #define xs 5 / 2 223 | #define ys 5 / 2 224 | #define zs 0 225 | //-------------------------------------------------------------- 226 | /* 227 | * Create an icon with the text 'icontext', and store in 'filename' 228 | * returns 0 on success, -1 on failure 229 | * 230 | * The position of the text is hard coded in on line 260 231 | */ 232 | //-------------------------------------------------------------- 233 | int make_icon(char *icontext, char *filename) 234 | { 235 | int i; 236 | struct icon_header icn_head; 237 | icn_head.icon_id = 0x010000; 238 | icn_head.anim_shapes = 0x01; 239 | icn_head.texture_type = 0x0E; //uncompressed=0x07 240 | icn_head.UNKNOWN = 0x3F800000; 241 | icn_head.num_vertices = 12; 242 | 243 | struct icon_vertex icn_vertices[12]; 244 | struct icon_texturedata texdata[12]; 245 | struct icon_vertex normals[4]; //numvertices/3, as 3 vertices share one normal 246 | //Back face //Triangle Vertices //Texture coordinates of vertices 247 | set_vv(normals[0], 0, 0, 1); 248 | set_vv(icn_vertices[0], -xs, -ys, zs); 249 | set_tv(texdata[0].uv, 1, 0); 250 | set_vv(icn_vertices[1], xs, -ys, zs); 251 | set_tv(texdata[1].uv, 0, 0); 252 | set_vv(icn_vertices[2], xs, ys, zs); 253 | set_tv(texdata[2].uv, 0, 1); 254 | set_vv(normals[1], 0, 0, 1); 255 | set_vv(icn_vertices[3], xs, ys, zs); 256 | set_tv(texdata[3].uv, 0, 1); 257 | set_vv(icn_vertices[4], -xs, ys, zs); 258 | set_tv(texdata[4].uv, 1, 1); 259 | set_vv(icn_vertices[5], -xs, -ys, zs); 260 | set_tv(texdata[5].uv, 1, 0); 261 | //Front face 262 | set_vv(normals[2], 0, 0, -1); 263 | set_vv(icn_vertices[6], xs, -ys, -zs); 264 | set_tv(texdata[6].uv, 1, 0); 265 | set_vv(icn_vertices[7], -xs, -ys, -zs); 266 | set_tv(texdata[7].uv, 0, 0); 267 | set_vv(icn_vertices[8], -xs, ys, -zs); 268 | set_tv(texdata[8].uv, 0, 1); 269 | set_vv(normals[3], 0, 0, -1); 270 | set_vv(icn_vertices[9], -xs, ys, -zs); 271 | set_tv(texdata[9].uv, 0, 1); 272 | set_vv(icn_vertices[10], xs, ys, -zs); 273 | set_tv(texdata[10].uv, 1, 1); 274 | set_vv(icn_vertices[11], xs, -ys, -zs); 275 | set_tv(texdata[11].uv, 1, 0); 276 | 277 | for (i = 0; i < icn_head.num_vertices; i++) { 278 | //the y values are generally too small, make them larger 279 | icn_vertices[i].xyz[1] -= ys * 4096; //subtract increases? 280 | texdata[i].rgba[0] = 0x80; 281 | texdata[i].rgba[1] = 0x80; 282 | texdata[i].rgba[2] = 0x80; 283 | texdata[i].rgba[3] = 0x80; 284 | } 285 | 286 | struct icon_animheader icn_anim_head; 287 | icn_anim_head.id = 0x01; 288 | icn_anim_head.frame_length = 1; 289 | icn_anim_head.anim_speed = 1; 290 | icn_anim_head.play_offset = 0; 291 | icn_anim_head.num_frames = 1; 292 | 293 | struct icon_framedata framedata; 294 | framedata.shapeid = 0; 295 | framedata.num_keys = 1; 296 | framedata.time = 1; 297 | framedata.value = 1; 298 | 299 | // allocates room for the texture and sets the background to black 300 | tex_buffer = malloc(128 * 128 * 2); // the entire 128x128 pixel image(16bpp) 301 | memset(tex_buffer, 0x00, 128 * 128 * 2); // black background 302 | tex_printXY(icontext, 0, 0, 0xFFFF); // (string,xpos,ypos,color) 303 | u32 tex_size = tex_compresRLE(); // compress the texture, overwrites tex_buffer 304 | 305 | FILE *f = fopen(filename, "wb"); //open/create the file 306 | if (f == NULL) 307 | return -1; 308 | fwrite(&icn_head, sizeof(icn_head), 1, f); 309 | for (i = 0; i < icn_head.num_vertices; i++) { 310 | fwrite(&icn_vertices[i], sizeof(icn_vertices[i]), 1, f); 311 | fwrite(&normals[i / 3], sizeof(normals[i / 3]), 1, f); 312 | fwrite(&texdata[i], sizeof(texdata[i]), 1, f); 313 | } 314 | fwrite(&icn_anim_head, sizeof(icn_anim_head), 1, f); 315 | fwrite(&framedata, 1, sizeof(framedata), f); 316 | fwrite(&tex_size, 4, 1, f); 317 | fwrite(tex_buffer, 1, tex_size, f); 318 | fclose(f); 319 | return 0; 320 | } 321 | //-------------------------------------------------------------- 322 | /* 323 | * This makes the icon.sys file that goes along with the icon itself 324 | * text is the text that the browser shows (max of 32 characters) 325 | * iconname is the icon file that it refers to(usually icon.icn/or icon.ico) 326 | * filename is where to store the icon.sys file(eg: mc0:/FOLDER/icon.sys) 327 | */ 328 | //-------------------------------------------------------------- 329 | int make_iconsys(char *title, char *iconname, char *filename) 330 | { 331 | // mcIcon is defined as part of libmc 332 | mcIcon icon_sys; 333 | 334 | memset(((void *)&icon_sys), 0, sizeof(icon_sys)); 335 | 336 | strcpy(icon_sys.head, "PS2D"); 337 | icon_sys.nlOffset = 0; //0=automagically wordwrap, otherwise newline position(multiple of 2) 338 | strcpy_sjis((short *)&icon_sys.title, title); 339 | 340 | icon_sys.trans = 0x40; 341 | // default values from mcIconSysGen 342 | iconIVECTOR bgcolor[4] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}; 343 | iconFVECTOR ambientlight = {1, 1, 1, 0}; 344 | iconFVECTOR lightdirection[3] = { 345 | {0.5, 0.5, 0.5, 0.0}, 346 | {0.0, 0.4, -0.1, 0.0}, 347 | {-0.5, -0.5, 0.5, 0.0}, 348 | }; 349 | iconFVECTOR lightcolors[3] = { 350 | {0.5, 0.5, 0.5, 0.00}, 351 | {0.7, 0.7, 0.7, 0.00}, 352 | {0.5, 0.5, 0.5, 0.00}, 353 | }; 354 | memcpy(icon_sys.bgCol, bgcolor, sizeof(bgcolor)); 355 | memcpy(icon_sys.lightDir, lightdirection, sizeof(lightdirection)); 356 | memcpy(icon_sys.lightCol, lightcolors, sizeof(lightcolors)); 357 | memcpy(icon_sys.lightAmbient, ambientlight, sizeof(ambientlight)); 358 | strcpy(icon_sys.view, iconname); 359 | strcpy(icon_sys.copy, iconname); 360 | strcpy(icon_sys.del, iconname); 361 | 362 | FILE *f = fopen(filename, "wb"); // open/create the file 363 | if (f == NULL) 364 | return -1; 365 | fwrite(&icon_sys, 1, sizeof(icon_sys), f); 366 | fclose(f); 367 | 368 | return 0; 369 | } 370 | //-------------------------------------------------------------- 371 | //End of file: makeicon.c 372 | //-------------------------------------------------------------- 373 | -------------------------------------------------------------------------------- /lang.c: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------------- 2 | //File name: lang.c 3 | //--------------------------------------------------------------------------- 4 | #include "launchelf.h" 5 | 6 | #define lang(id, name, value) u8 Str_##name[] = value; 7 | #include "lang.h" 8 | #undef lang 9 | 10 | Language Lang_Default[] = { 11 | #define lang(id, name, value) {Str_##name}, 12 | #include "lang.h" 13 | #undef lang 14 | {NULL}}; 15 | 16 | Language Lang_String[sizeof(Lang_Default) / sizeof(Lang_Default[0])]; 17 | Language Lang_Extern[sizeof(Lang_Default) / sizeof(Lang_Default[0])]; 18 | 19 | Language *External_Lang_Buffer = NULL; 20 | 21 | //--------------------------------------------------------------------------- 22 | // get_LANG_string is the main parser called for each language dependent 23 | // string in a language header file. (eg: "Francais.h" or "Francais.lng") 24 | // Call values for all input arguments should be addresses of string pointers 25 | // LANG_p_p is for file to be scanned, moved to point beyond scanned data. 26 | // id_p_p is for a string defining the index value (suitable for 'atoi') 27 | // value_p_p is for the string value itself (not NUL-terminated) 28 | // The function returns the length of each string found, but -1 at EOF, 29 | // and various error codes less than -1 (-2 etc) for various syntax errors, 30 | // which also applies to EOF occurring where valid macro parts are expected. 31 | //--------------------------------------------------------------------------- 32 | int get_LANG_string(u8 **LANG_p_p, u8 **id_p_p, u8 **value_p_p) 33 | { 34 | u8 *cp, *ip, *vp, *tp = *LANG_p_p; 35 | int ret, length; 36 | 37 | ip = NULL; 38 | vp = NULL; 39 | ret = -1; 40 | 41 | start_line: 42 | while (*tp <= ' ' && *tp > '\0') 43 | tp += 1; //Skip leading whitespace, if any 44 | if (*tp == '\0') 45 | goto exit; //but exit at EOF 46 | //Current pos is potential "lang(" entry, but we must verify this 47 | if (tp[0] == '/' && tp[1] == '/') //It may be a comment line 48 | { //We must skip a comment line 49 | while (*tp != '\r' && *tp != '\n' && *tp > '\0') 50 | tp += 1; //Seek line end 51 | goto start_line; //Go back to try next line 52 | } 53 | ret = -2; 54 | //Here tp points to a non-zero string that is not a comment 55 | if (strncmp(tp, "lang", 4)) 56 | goto exit; //Return error if not 'lang' macro 57 | tp += 4; //but if it is, step past that name 58 | ret = -3; 59 | while (*tp <= ' ' && *tp != '\r' && *tp != '\n' && *tp > '\0') 60 | tp += 1; //skip inline whitespace 61 | if (*tp == '\0') 62 | goto exit; //but exit at EOF 63 | ret = -4; 64 | //Here tp points to a non-zero string that should be an opening parenthesis 65 | if (*tp != '(') 66 | goto exit; //Return error if no opening parenthesis 67 | tp += 1; //but if it is, step past this character 68 | ret = -5; 69 | while (*tp <= ' ' && *tp != '\r' && *tp != '\n' && *tp > '\0') 70 | tp += 1; //skip inline whitespace 71 | if (*tp == '\0') 72 | goto exit; //but exit at EOF 73 | ret = -6; 74 | //Here tp points to a non-zero string that should be an index number 75 | if (*tp < '0' || *tp > '9') 76 | goto exit; //Return error if it's not a number 77 | ip = tp; //but if it is, save this pos as id start 78 | while (*tp >= '0' && *tp <= '9') 79 | tp += 1; //skip past the index number 80 | ret = -7; 81 | while (*tp <= ' ' && *tp != '\r' && *tp != '\n' && *tp > '\0') 82 | tp += 1; //skip inline whitespace 83 | if (*tp == '\0') 84 | goto exit; //but exit at EOF 85 | ret = -8; 86 | //Here tp points to a non-zero string that should be a comma 87 | if (*tp != ',') 88 | goto exit; //Return error if no comma after index 89 | tp += 1; //but if present, step past that comma 90 | ret = -9; 91 | while (*tp <= ' ' && *tp != '\r' && *tp != '\n' && *tp > '\0') 92 | tp += 1; //skip inline whitespace 93 | if (*tp == '\0') 94 | goto exit; //but exit at EOF 95 | ret = -10; 96 | //Here tp points to a non-zero string that should be a symbolic string name 97 | //But we don't need to process this for language switch purposes, so we ignore it 98 | //This may be changed later, to use the name for generating error messages 99 | while (*tp != ',' && *tp != '\r' && *tp != '\n' && *tp > '\0') 100 | tp += 1; //seek inline comma 101 | if (*tp != ',') 102 | goto exit; //Return error if no comma after string name 103 | tp += 1; //but if present, step past that comma 104 | ret = -11; 105 | while (*tp <= ' ' && *tp != '\r' && *tp != '\n' && *tp > '\0') 106 | tp += 1; //skip inline whitespace 107 | if (*tp == '\0') 108 | goto exit; //but exit at EOF 109 | ret = -12; 110 | //Here tp points to a non-zero string that should be the opening quote character 111 | if (*tp != '\"') 112 | goto exit; //Return error if no opening quote 113 | tp += 1; //but if present, step past that quote 114 | ret = -13; 115 | vp = tp; //save this pos as value start 116 | close_quote: 117 | while (*tp != '\"' && *tp != '\r' && *tp != '\n' && *tp > '\0') 118 | tp += 1; //seek inline quote 119 | if (*tp != '\"') 120 | return -13; //Return error if no closing quote 121 | cp = tp - 1; //save previous pos as check pointer 122 | tp += 1; //step past the quote character 123 | if (*cp == '\\') 124 | goto close_quote; //if this was an 'escaped' quote, try again 125 | //Here tp points to the character after the closing quote. 126 | length = (tp - 1) - vp; //prepare string length for return value 127 | ret = -14; 128 | while (*tp <= ' ' && *tp != '\r' && *tp != '\n' && *tp > '\0') 129 | tp += 1; //skip inline whitespace 130 | if (*tp == '\0') 131 | goto exit; //but exit at EOF 132 | ret = -15; 133 | //Here tp points to a non-zero string that should be closing parenthesis 134 | if (*tp != ')') 135 | goto exit; //Return error if no closing parenthesis 136 | tp += 1; //but if present, step past the parenthesis 137 | ret = -16; 138 | while (*tp <= ' ' && *tp != '\r' && *tp != '\n' && *tp > '\0') 139 | tp += 1; //skip inline whitespace 140 | if (*tp == '\0') 141 | goto exit; //but exit at EOF 142 | //Here tp points to a non-zero string that should be line end or a comment 143 | if (tp[0] != '/' || tp[1] != '/') 144 | goto finish_line; //if no comment, go handle line end 145 | ret = -17; 146 | while (*tp != '\r' && *tp != '\n' && *tp > '\0') 147 | tp += 1; //Seek line end 148 | if (*tp == '\0') 149 | goto exit; //but exit at EOF 150 | finish_line: 151 | ret = -18; 152 | if (*tp != '\r' && *tp != '\n') 153 | goto exit; //Return error if not valid line end 154 | if (tp[0] == '\r' && tp[1] == '\n') 155 | tp += 1; //Step an extra pos for CR+LF 156 | tp += 1; //Step past valid line end 157 | //Here tp points beyond the line of the processed string, so we're done 158 | ret = length; 159 | 160 | exit: 161 | *LANG_p_p = tp; //return new LANG file position 162 | *id_p_p = ip; //return found index 163 | *value_p_p = vp; //return found string value 164 | return ret; //return control to caller 165 | } 166 | //Ends get_LANG_string 167 | //--------------------------------------------------------------------------- 168 | void Init_Default_Language(void) 169 | { 170 | memcpy(Lang_String, Lang_Default, sizeof(Lang_String)); 171 | } 172 | //Ends Init_Default_Language 173 | //--------------------------------------------------------------------------- 174 | void Load_External_Language(void) 175 | { 176 | int error_id = -1; 177 | int test = 0; 178 | u32 index = 0; 179 | char filePath[MAX_PATH]; 180 | u8 *file_bp, *file_tp, *lang_bp, *lang_tp, *oldf_tp = NULL; 181 | u8 *id_p, *value_p; 182 | int lang_size = 0; 183 | int fd; 184 | 185 | if (External_Lang_Buffer != NULL) { //if an external buffer was allocated before 186 | free(External_Lang_Buffer); //release that buffer before the new attempt 187 | External_Lang_Buffer = NULL; 188 | } 189 | 190 | Language *Lang = Lang_Default; 191 | memcpy(Lang_String, Lang, sizeof(Lang_String)); 192 | 193 | if (strlen(setting->lang_file) != 0) { //if language file string set 194 | 195 | error_id = -2; 196 | genFixPath(setting->lang_file, filePath); 197 | fd = genOpen(filePath, O_RDONLY); 198 | if (fd >= 0) { //if file opened OK 199 | int file_size = genLseek(fd, 0, SEEK_END); 200 | 201 | error_id = -3; 202 | if (file_size > 0) { //if file size OK 203 | error_id = -4; 204 | file_bp = (u8 *)malloc(file_size + 1); 205 | if (file_bp == NULL) 206 | goto aborted_1; 207 | 208 | error_id = -5; 209 | genLseek(fd, 0, SEEK_SET); 210 | if (genRead(fd, file_bp, file_size) != file_size) 211 | goto release_1; 212 | file_bp[file_size] = '\0'; //enforce termination at buffer end 213 | 214 | error_id = -6; 215 | file_tp = file_bp; 216 | while (1) { 217 | oldf_tp = file_tp; 218 | test = get_LANG_string(&file_tp, &id_p, &value_p); 219 | if (test == -1) //if EOF reached without other error 220 | break; //break from the loop normally 221 | if (test < 0) //At any fatal error result 222 | goto release_1; //go release file buffer 223 | index = atoi(id_p); //get the string index 224 | if (index >= LANG_COUNT) //At any fatal error result 225 | goto release_1; //go release file buffer 226 | lang_size += test + 1; //Include terminator space for total size 227 | } 228 | //Here lang_size is the space needed for real language buffer, 229 | 230 | error_id = -7; 231 | lang_bp = (u8 *)malloc(lang_size + 1); //allocate real language buffer 232 | if (lang_bp == NULL) 233 | goto release_1; 234 | 235 | //We're ready to read language strings, but must first init all pointers 236 | //to use default strings, for any indexes left undefined by the file 237 | memcpy(Lang_Extern, Lang, sizeof(Lang_Extern)); 238 | 239 | file_tp = file_bp; 240 | lang_tp = lang_bp; 241 | while ((test = get_LANG_string(&file_tp, &id_p, &value_p)) >= 0) { 242 | index = atoi(id_p); //get the string index 243 | Lang_Extern[index].String = lang_tp; //save pointer to this string base 244 | strncpy(lang_tp, value_p, test); //transfer the string 245 | lang_tp[test] = '\0'; //transfer a terminator 246 | lang_tp += test + 1; //move dest pointer past this string 247 | } 248 | External_Lang_Buffer = (Language *)lang_bp; //Save base pointer for releases 249 | Lang = Lang_Extern; 250 | error_id = 0; 251 | release_1: 252 | free(file_bp); 253 | } // end if clause for file size OK 254 | aborted_1: 255 | genClose(fd); 256 | } // end if clause for file opened OK 257 | } // end if language file string set 258 | 259 | if (error_id < -1) { 260 | u8 tmp_s[80 * 8], t1_s[102], t2_s[102]; 261 | int pos = 0, stp = 0; 262 | sprintf(tmp_s, 263 | "LNG loading failed with error_id==%d and test==%d\n" 264 | "The latest string index (possibly invalid) was %d\n" 265 | "%n", 266 | error_id, test, index, &stp); 267 | pos += stp; 268 | if (error_id == -2) { //if file open failure 269 | sprintf(tmp_s + pos, 270 | "This was a failure to open the file:\n" 271 | "\"%s\"\n", 272 | filePath); 273 | } 274 | if (error_id == -6) { //if parsing error 275 | strncpy(t1_s, oldf_tp, 100); 276 | t1_s[100] = '\0'; 277 | strncpy(t2_s, file_tp, 100); 278 | t2_s[100] = '\0'; 279 | sprintf(tmp_s + pos, 280 | "This was a parsing error when trying to parse the text:\n" 281 | "\"%s\"\n" 282 | "That attempt failed somehow, after reaching this point:\n" 283 | "\"%s\"\n", 284 | t1_s, t2_s); 285 | } 286 | strcat(tmp_s, "Use either OK or CANCEL to continue (no diff)"); 287 | ynDialog(tmp_s); 288 | } 289 | 290 | memcpy(Lang_String, Lang, sizeof(Lang_String)); 291 | 292 | int i; 293 | char *tmp; 294 | 295 | if (strlen(setting->Misc) > 0) { 296 | for (i = 0; i < 16; i++) { //Loop to rename the ELF paths with new language for launch keys 297 | if ((i < 12) || (setting->LK_Flag[i] != 0)) { 298 | if (!strncmp(setting->LK_Path[i], setting->Misc, strlen(setting->Misc))) { 299 | tmp = strrchr(setting->LK_Path[i], '/'); 300 | if (!strcmp(tmp + 1, setting->Misc_PS2Disc + strlen(setting->Misc))) 301 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(PS2Disc)); 302 | else if (!strcmp(tmp + 1, setting->Misc_FileBrowser + strlen(setting->Misc))) 303 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(FileBrowser)); 304 | else if (!strcmp(tmp + 1, setting->Misc_PS2Browser + strlen(setting->Misc))) 305 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(PS2Browser)); 306 | else if (!strcmp(tmp + 1, setting->Misc_PS2Net + strlen(setting->Misc))) 307 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(PS2Net)); 308 | else if (!strcmp(tmp + 1, setting->Misc_PS2PowerOff + strlen(setting->Misc))) 309 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(PS2PowerOff)); 310 | else if (!strcmp(tmp + 1, setting->Misc_HddManager + strlen(setting->Misc))) 311 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(HddManager)); 312 | else if (!strcmp(tmp + 1, setting->Misc_TextEditor + strlen(setting->Misc))) 313 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(TextEditor)); 314 | else if (!strcmp(tmp + 1, setting->Misc_JpgViewer + strlen(setting->Misc))) 315 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(JpgViewer)); 316 | else if (!strcmp(tmp + 1, setting->Misc_Configure + strlen(setting->Misc))) 317 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(Configure)); 318 | else if (!strcmp(tmp + 1, setting->Misc_Load_CNFprev + strlen(setting->Misc))) 319 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(Load_CNFprev)); 320 | else if (!strcmp(tmp + 1, setting->Misc_Load_CNFnext + strlen(setting->Misc))) 321 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(Load_CNFnext)); 322 | else if (!strcmp(tmp + 1, setting->Misc_Set_CNF_Path + strlen(setting->Misc))) 323 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(Set_CNF_Path)); 324 | else if (!strcmp(tmp + 1, setting->Misc_Load_CNF + strlen(setting->Misc))) 325 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(Load_CNF)); 326 | else if (!strcmp(tmp + 1, setting->Misc_ShowFont + strlen(setting->Misc))) 327 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(ShowFont)); 328 | else if (!strcmp(tmp + 1, setting->Misc_Debug_Info + strlen(setting->Misc))) 329 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(Debug_Info)); 330 | else if (!strcmp(tmp + 1, setting->Misc_About_uLE + strlen(setting->Misc))) 331 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(About_uLE)); 332 | else if (!strcmp(tmp + 1, setting->Misc_OSDSYS + strlen(setting->Misc))) 333 | sprintf(setting->LK_Path[i], "%s/%s", LNG(MISC), LNG(OSDSYS)); 334 | } // end if Misc 335 | } // end if LK assigned 336 | } // end for 337 | } // end if Misc Initialized 338 | 339 | sprintf(setting->Misc, "%s/", LNG(MISC)); 340 | sprintf(setting->Misc_PS2Disc, "%s/%s", LNG(MISC), LNG(PS2Disc)); 341 | sprintf(setting->Misc_FileBrowser, "%s/%s", LNG(MISC), LNG(FileBrowser)); 342 | sprintf(setting->Misc_PS2Browser, "%s/%s", LNG(MISC), LNG(PS2Browser)); 343 | sprintf(setting->Misc_PS2Net, "%s/%s", LNG(MISC), LNG(PS2Net)); 344 | sprintf(setting->Misc_PS2PowerOff, "%s/%s", LNG(MISC), LNG(PS2PowerOff)); 345 | sprintf(setting->Misc_HddManager, "%s/%s", LNG(MISC), LNG(HddManager)); 346 | sprintf(setting->Misc_TextEditor, "%s/%s", LNG(MISC), LNG(TextEditor)); 347 | sprintf(setting->Misc_JpgViewer, "%s/%s", LNG(MISC), LNG(JpgViewer)); 348 | sprintf(setting->Misc_Configure, "%s/%s", LNG(MISC), LNG(Configure)); 349 | sprintf(setting->Misc_Load_CNFprev, "%s/%s", LNG(MISC), LNG(Load_CNFprev)); 350 | sprintf(setting->Misc_Load_CNFnext, "%s/%s", LNG(MISC), LNG(Load_CNFnext)); 351 | sprintf(setting->Misc_Set_CNF_Path, "%s/%s", LNG(MISC), LNG(Set_CNF_Path)); 352 | sprintf(setting->Misc_Load_CNF, "%s/%s", LNG(MISC), LNG(Load_CNF)); 353 | sprintf(setting->Misc_ShowFont, "%s/%s", LNG(MISC), LNG(ShowFont)); 354 | sprintf(setting->Misc_Debug_Info, "%s/%s", LNG(MISC), LNG(Debug_Info)); 355 | sprintf(setting->Misc_About_uLE, "%s/%s", LNG(MISC), LNG(About_uLE)); 356 | sprintf(setting->Misc_OSDSYS, "%s/%s", LNG(MISC), LNG(OSDSYS)); 357 | } 358 | //Ends Load_External_Language 359 | //--------------------------------------------------------------------------- 360 | //End of file: lang.c 361 | //--------------------------------------------------------------------------- 362 | --------------------------------------------------------------------------------