diff options
Diffstat (limited to 'src')
28 files changed, 534 insertions, 525 deletions
diff --git a/src/common/common_paths.h b/src/common/common_paths.h index 42e1a29c1..a86889756 100644 --- a/src/common/common_paths.h +++ b/src/common/common_paths.h | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #define MAPS_DIR "maps" | 40 | #define MAPS_DIR "maps" |
| 41 | #define CACHE_DIR "cache" | 41 | #define CACHE_DIR "cache" |
| 42 | #define SDMC_DIR "sdmc" | 42 | #define SDMC_DIR "sdmc" |
| 43 | #define SAVEDATA_DIR "savedata" | ||
| 43 | #define SYSDATA_DIR "sysdata" | 44 | #define SYSDATA_DIR "sysdata" |
| 44 | #define SHADERCACHE_DIR "shader_cache" | 45 | #define SHADERCACHE_DIR "shader_cache" |
| 45 | #define STATESAVES_DIR "state_saves" | 46 | #define STATESAVES_DIR "state_saves" |
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 88c46c117..42cdf3262 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -676,6 +676,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new | |||
| 676 | paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; | 676 | paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; |
| 677 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; | 677 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; |
| 678 | paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; | 678 | paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; |
| 679 | paths[D_SAVEDATA_IDX] = paths[D_USER_IDX] + SAVEDATA_DIR DIR_SEP; | ||
| 679 | paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP; | 680 | paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP; |
| 680 | paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; | 681 | paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; |
| 681 | paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; | 682 | paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; |
| @@ -718,6 +719,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new | |||
| 718 | paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; | 719 | paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; |
| 719 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; | 720 | paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; |
| 720 | paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; | 721 | paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; |
| 722 | paths[D_SAVEDATA_IDX] = paths[D_USER_IDX] + SAVEDATA_DIR DIR_SEP; | ||
| 721 | paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; | 723 | paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; |
| 722 | paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; | 724 | paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; |
| 723 | paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; | 725 | paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; |
diff --git a/src/common/file_util.h b/src/common/file_util.h index a9d48cfe8..e691b6139 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h | |||
| @@ -27,6 +27,7 @@ enum { | |||
| 27 | D_STATESAVES_IDX, | 27 | D_STATESAVES_IDX, |
| 28 | D_SCREENSHOTS_IDX, | 28 | D_SCREENSHOTS_IDX, |
| 29 | D_SDMC_IDX, | 29 | D_SDMC_IDX, |
| 30 | D_SAVEDATA_IDX, | ||
| 30 | D_SYSDATA_IDX, | 31 | D_SYSDATA_IDX, |
| 31 | D_HIRESTEXTURES_IDX, | 32 | D_HIRESTEXTURES_IDX, |
| 32 | D_DUMP_IDX, | 33 | D_DUMP_IDX, |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 198e4afd3..f71232c1a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -18,11 +18,11 @@ set(SRCS | |||
| 18 | arm/skyeye_common/vfp/vfpinstr.cpp | 18 | arm/skyeye_common/vfp/vfpinstr.cpp |
| 19 | arm/skyeye_common/vfp/vfpsingle.cpp | 19 | arm/skyeye_common/vfp/vfpsingle.cpp |
| 20 | file_sys/archive_romfs.cpp | 20 | file_sys/archive_romfs.cpp |
| 21 | file_sys/archive_savedata.cpp | ||
| 21 | file_sys/archive_sdmc.cpp | 22 | file_sys/archive_sdmc.cpp |
| 23 | file_sys/disk_archive.cpp | ||
| 22 | file_sys/file_romfs.cpp | 24 | file_sys/file_romfs.cpp |
| 23 | file_sys/file_sdmc.cpp | ||
| 24 | file_sys/directory_romfs.cpp | 25 | file_sys/directory_romfs.cpp |
| 25 | file_sys/directory_sdmc.cpp | ||
| 26 | hle/kernel/address_arbiter.cpp | 26 | hle/kernel/address_arbiter.cpp |
| 27 | hle/kernel/event.cpp | 27 | hle/kernel/event.cpp |
| 28 | hle/kernel/kernel.cpp | 28 | hle/kernel/kernel.cpp |
| @@ -99,13 +99,13 @@ set(HEADERS | |||
| 99 | arm/arm_interface.h | 99 | arm/arm_interface.h |
| 100 | file_sys/archive_backend.h | 100 | file_sys/archive_backend.h |
| 101 | file_sys/archive_romfs.h | 101 | file_sys/archive_romfs.h |
| 102 | file_sys/archive_savedata.h | ||
| 102 | file_sys/archive_sdmc.h | 103 | file_sys/archive_sdmc.h |
| 104 | file_sys/disk_archive.h | ||
| 103 | file_sys/file_backend.h | 105 | file_sys/file_backend.h |
| 104 | file_sys/file_romfs.h | 106 | file_sys/file_romfs.h |
| 105 | file_sys/file_sdmc.h | ||
| 106 | file_sys/directory_backend.h | 107 | file_sys/directory_backend.h |
| 107 | file_sys/directory_romfs.h | 108 | file_sys/directory_romfs.h |
| 108 | file_sys/directory_sdmc.h | ||
| 109 | hle/kernel/address_arbiter.h | 109 | hle/kernel/address_arbiter.h |
| 110 | hle/kernel/event.h | 110 | hle/kernel/event.h |
| 111 | hle/kernel/kernel.h | 111 | hle/kernel/kernel.h |
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index b207416dd..3b1a36bdd 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp | |||
| @@ -1356,7 +1356,13 @@ mainswitch: | |||
| 1356 | } | 1356 | } |
| 1357 | break; | 1357 | break; |
| 1358 | 1358 | ||
| 1359 | case 0x04: /* SUB reg */ | 1359 | case 0x04: /* SUB reg */ |
| 1360 | // Signifies UMAAL | ||
| 1361 | if (state->is_v6 && BITS(4, 7) == 0x09) { | ||
| 1362 | if (handle_v6_insn(state, instr)) | ||
| 1363 | break; | ||
| 1364 | } | ||
| 1365 | |||
| 1360 | #ifdef MODET | 1366 | #ifdef MODET |
| 1361 | if (BITS (4, 7) == 0xB) { | 1367 | if (BITS (4, 7) == 0xB) { |
| 1362 | /* STRH immediate offset, no write-back, down, post indexed. */ | 1368 | /* STRH immediate offset, no write-back, down, post indexed. */ |
| @@ -3103,12 +3109,18 @@ mainswitch: | |||
| 3103 | state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000); | 3109 | state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000); |
| 3104 | break; | 3110 | break; |
| 3105 | } else if ((instr & 0x70) == 0x50) { //pkhtb | 3111 | } else if ((instr & 0x70) == 0x50) { //pkhtb |
| 3106 | u8 idest = BITS(12, 15); | 3112 | const u8 rd_idx = BITS(12, 15); |
| 3107 | u8 rfis = BITS(16, 19); | 3113 | const u8 rn_idx = BITS(16, 19); |
| 3108 | u8 rlast = BITS(0, 3); | 3114 | const u8 rm_idx = BITS(0, 3); |
| 3109 | u8 ishi = BITS(7, 11); | 3115 | const u8 imm5 = BITS(7, 11); |
| 3110 | if (ishi == 0)ishi = 0x20; | 3116 | |
| 3111 | state->Reg[idest] = (((int)(state->Reg[rlast]) >> (int)(ishi))& 0xFFFF) | ((state->Reg[rfis]) & 0xFFFF0000); | 3117 | ARMword val; |
| 3118 | if (imm5 >= 32) | ||
| 3119 | val = (state->Reg[rm_idx] >> 31); | ||
| 3120 | else | ||
| 3121 | val = (state->Reg[rm_idx] >> imm5); | ||
| 3122 | |||
| 3123 | state->Reg[rd_idx] = (val & 0xFFFF) | ((state->Reg[rn_idx]) & 0xFFFF0000); | ||
| 3112 | break; | 3124 | break; |
| 3113 | } else if (BIT (4)) { | 3125 | } else if (BIT (4)) { |
| 3114 | #ifdef MODE32 | 3126 | #ifdef MODE32 |
| @@ -5677,8 +5689,24 @@ L_stm_s_takeabort: | |||
| 5677 | case 0x03: | 5689 | case 0x03: |
| 5678 | printf ("Unhandled v6 insn: ldr\n"); | 5690 | printf ("Unhandled v6 insn: ldr\n"); |
| 5679 | break; | 5691 | break; |
| 5680 | case 0x04: | 5692 | case 0x04: // UMAAL |
| 5681 | printf ("Unhandled v6 insn: umaal\n"); | 5693 | { |
| 5694 | const u8 rm_idx = BITS(8, 11); | ||
| 5695 | const u8 rn_idx = BITS(0, 3); | ||
| 5696 | const u8 rd_lo_idx = BITS(12, 15); | ||
| 5697 | const u8 rd_hi_idx = BITS(16, 19); | ||
| 5698 | |||
| 5699 | const u32 rm_val = state->Reg[rm_idx]; | ||
| 5700 | const u32 rn_val = state->Reg[rn_idx]; | ||
| 5701 | const u32 rd_lo_val = state->Reg[rd_lo_idx]; | ||
| 5702 | const u32 rd_hi_val = state->Reg[rd_hi_idx]; | ||
| 5703 | |||
| 5704 | const u64 result = (rn_val * rm_val) + rd_lo_val + rd_hi_val; | ||
| 5705 | |||
| 5706 | state->Reg[rd_lo_idx] = (result & 0xFFFFFFFF); | ||
| 5707 | state->Reg[rd_hi_idx] = ((result >> 32) & 0xFFFFFFFF); | ||
| 5708 | return 1; | ||
| 5709 | } | ||
| 5682 | break; | 5710 | break; |
| 5683 | case 0x06: | 5711 | case 0x06: |
| 5684 | printf ("Unhandled v6 insn: mls/str\n"); | 5712 | printf ("Unhandled v6 insn: mls/str\n"); |
| @@ -5801,14 +5829,14 @@ L_stm_s_takeabort: | |||
| 5801 | break; | 5829 | break; |
| 5802 | case 0x61: | 5830 | case 0x61: |
| 5803 | if ((instr & 0xFF0) == 0xf70) { //ssub16 | 5831 | if ((instr & 0xFF0) == 0xf70) { //ssub16 |
| 5804 | u8 tar = BITS(12, 15); | 5832 | const u8 rd_idx = BITS(12, 15); |
| 5805 | u8 src1 = BITS(16, 19); | 5833 | const u8 rm_idx = BITS(0, 3); |
| 5806 | u8 src2 = BITS(0, 3); | 5834 | const u8 rn_idx = BITS(16, 19); |
| 5807 | s16 a1 = (state->Reg[src1] & 0xFFFF); | 5835 | const s16 rn_lo = (state->Reg[rn_idx] & 0xFFFF); |
| 5808 | s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); | 5836 | const s16 rn_hi = ((state->Reg[rn_idx] >> 16) & 0xFFFF); |
| 5809 | s16 b1 = (state->Reg[src2] & 0xFFFF); | 5837 | const s16 rm_lo = (state->Reg[rm_idx] & 0xFFFF); |
| 5810 | s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); | 5838 | const s16 rm_hi = ((state->Reg[rm_idx] >> 16) & 0xFFFF); |
| 5811 | state->Reg[tar] = ((a1 - a2) & 0xFFFF) | (((b1 - b2) & 0xFFFF) << 0x10); | 5839 | state->Reg[rd_idx] = ((rn_lo - rm_lo) & 0xFFFF) | (((rn_hi - rm_hi) & 0xFFFF) << 16); |
| 5812 | return 1; | 5840 | return 1; |
| 5813 | } else if ((instr & 0xFF0) == 0xf10) { //sadd16 | 5841 | } else if ((instr & 0xFF0) == 0xf10) { //sadd16 |
| 5814 | const u8 rd_idx = BITS(12, 15); | 5842 | const u8 rd_idx = BITS(12, 15); |
| @@ -6067,7 +6095,7 @@ L_stm_s_takeabort: | |||
| 6067 | break; | 6095 | break; |
| 6068 | } | 6096 | } |
| 6069 | 6097 | ||
| 6070 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF); | 6098 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF; |
| 6071 | if (Rm & 0x80) | 6099 | if (Rm & 0x80) |
| 6072 | Rm |= 0xffffff00; | 6100 | Rm |= 0xffffff00; |
| 6073 | 6101 | ||
| @@ -6076,11 +6104,12 @@ L_stm_s_takeabort: | |||
| 6076 | state->Reg[BITS(12, 15)] = Rm; | 6104 | state->Reg[BITS(12, 15)] = Rm; |
| 6077 | else | 6105 | else |
| 6078 | /* SXTAB */ | 6106 | /* SXTAB */ |
| 6079 | state->Reg[BITS(12, 15)] += Rm; | 6107 | state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + Rm; |
| 6080 | 6108 | ||
| 6081 | return 1; | 6109 | return 1; |
| 6082 | } | 6110 | } |
| 6083 | case 0x6b: { | 6111 | case 0x6b: |
| 6112 | { | ||
| 6084 | ARMword Rm; | 6113 | ARMword Rm; |
| 6085 | int ror = -1; | 6114 | int ror = -1; |
| 6086 | 6115 | ||
| @@ -6098,10 +6127,10 @@ L_stm_s_takeabort: | |||
| 6098 | ror = 24; | 6127 | ror = 24; |
| 6099 | break; | 6128 | break; |
| 6100 | 6129 | ||
| 6101 | case 0xf3: | 6130 | case 0xf3: // REV |
| 6102 | DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24); | 6131 | DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24); |
| 6103 | return 1; | 6132 | return 1; |
| 6104 | case 0xfb: | 6133 | case 0xfb: // REV16 |
| 6105 | DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8); | 6134 | DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8); |
| 6106 | return 1; | 6135 | return 1; |
| 6107 | default: | 6136 | default: |
| @@ -6111,7 +6140,7 @@ L_stm_s_takeabort: | |||
| 6111 | if (ror == -1) | 6140 | if (ror == -1) |
| 6112 | break; | 6141 | break; |
| 6113 | 6142 | ||
| 6114 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF); | 6143 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF; |
| 6115 | if (Rm & 0x8000) | 6144 | if (Rm & 0x8000) |
| 6116 | Rm |= 0xffff0000; | 6145 | Rm |= 0xffff0000; |
| 6117 | 6146 | ||
| @@ -6198,7 +6227,7 @@ L_stm_s_takeabort: | |||
| 6198 | break; | 6227 | break; |
| 6199 | } | 6228 | } |
| 6200 | 6229 | ||
| 6201 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF); | 6230 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFF) & 0xFF; |
| 6202 | 6231 | ||
| 6203 | if (BITS(16, 19) == 0xf) | 6232 | if (BITS(16, 19) == 0xf) |
| 6204 | /* UXTB */ | 6233 | /* UXTB */ |
| @@ -6228,9 +6257,13 @@ L_stm_s_takeabort: | |||
| 6228 | ror = 24; | 6257 | ror = 24; |
| 6229 | break; | 6258 | break; |
| 6230 | 6259 | ||
| 6231 | case 0xfb: | 6260 | case 0xfb: // REVSH |
| 6232 | printf("Unhandled v6 insn: revsh\n"); | 6261 | { |
| 6233 | return 0; | 6262 | DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00) >> 8); |
| 6263 | if (DEST & 0x8000) | ||
| 6264 | DEST |= 0xffff0000; | ||
| 6265 | return 1; | ||
| 6266 | } | ||
| 6234 | default: | 6267 | default: |
| 6235 | break; | 6268 | break; |
| 6236 | } | 6269 | } |
| @@ -6238,13 +6271,13 @@ L_stm_s_takeabort: | |||
| 6238 | if (ror == -1) | 6271 | if (ror == -1) |
| 6239 | break; | 6272 | break; |
| 6240 | 6273 | ||
| 6241 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF); | 6274 | Rm = ((state->Reg[BITS(0, 3)] >> ror) & 0xFFFF) | ((state->Reg[BITS(0, 3)] << (32 - ror)) & 0xFFFF) & 0xFFFF; |
| 6242 | 6275 | ||
| 6243 | /* UXT */ | 6276 | /* UXT */ |
| 6244 | /* state->Reg[BITS (12, 15)] = Rm; */ | 6277 | /* state->Reg[BITS (12, 15)] = Rm; */ |
| 6245 | /* dyf add */ | 6278 | /* dyf add */ |
| 6246 | if (BITS(16, 19) == 0xf) { | 6279 | if (BITS(16, 19) == 0xf) { |
| 6247 | state->Reg[BITS(12, 15)] = (Rm >> (8 * BITS(10, 11))) & 0x0000FFFF; | 6280 | state->Reg[BITS(12, 15)] = Rm; |
| 6248 | } | 6281 | } |
| 6249 | else { | 6282 | else { |
| 6250 | /* UXTAH */ | 6283 | /* UXTAH */ |
| @@ -6252,7 +6285,7 @@ L_stm_s_takeabort: | |||
| 6252 | // printf("rd is %x rn is %x rm is %x rotate is %x\n", state->Reg[BITS (12, 15)], state->Reg[BITS (16, 19)] | 6285 | // printf("rd is %x rn is %x rm is %x rotate is %x\n", state->Reg[BITS (12, 15)], state->Reg[BITS (16, 19)] |
| 6253 | // , Rm, BITS(10, 11)); | 6286 | // , Rm, BITS(10, 11)); |
| 6254 | // printf("icounter is %lld\n", state->NumInstrs); | 6287 | // printf("icounter is %lld\n", state->NumInstrs); |
| 6255 | state->Reg[BITS(12, 15)] = (state->Reg[BITS(16, 19)] >> (8 * (BITS(10, 11)))) + Rm; | 6288 | state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + Rm; |
| 6256 | // printf("rd is %x\n", state->Reg[BITS (12, 15)]); | 6289 | // printf("rd is %x\n", state->Reg[BITS (12, 15)]); |
| 6257 | // exit(-1); | 6290 | // exit(-1); |
| 6258 | } | 6291 | } |
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp new file mode 100644 index 000000000..2414564e4 --- /dev/null +++ b/src/core/file_sys/archive_savedata.cpp | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2+ | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <sys/stat.h> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | |||
| 10 | #include "core/file_sys/archive_savedata.h" | ||
| 11 | #include "core/file_sys/disk_archive.h" | ||
| 12 | #include "core/settings.h" | ||
| 13 | |||
| 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 15 | // FileSys namespace | ||
| 16 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | Archive_SaveData::Archive_SaveData(const std::string& mount_point, u64 program_id) | ||
| 20 | : DiskArchive(mount_point + Common::StringFromFormat("%016X", program_id) + DIR_SEP) { | ||
| 21 | LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str()); | ||
| 22 | } | ||
| 23 | |||
| 24 | bool Archive_SaveData::Initialize() { | ||
| 25 | if (!FileUtil::CreateFullPath(mount_point)) { | ||
| 26 | LOG_ERROR(Service_FS, "Unable to create SaveData path."); | ||
| 27 | return false; | ||
| 28 | } | ||
| 29 | |||
| 30 | return true; | ||
| 31 | } | ||
| 32 | |||
| 33 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h new file mode 100644 index 000000000..b3e561130 --- /dev/null +++ b/src/core/file_sys/archive_savedata.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2+ | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | #include "core/file_sys/disk_archive.h" | ||
| 10 | #include "core/loader/loader.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // FileSys namespace | ||
| 14 | |||
| 15 | namespace FileSys { | ||
| 16 | |||
| 17 | /// File system interface to the SaveData archive | ||
| 18 | class Archive_SaveData final : public DiskArchive { | ||
| 19 | public: | ||
| 20 | Archive_SaveData(const std::string& mount_point, u64 program_id); | ||
| 21 | |||
| 22 | /** | ||
| 23 | * Initialize the archive. | ||
| 24 | * @return CreateSaveDataResult AlreadyExists if the SaveData folder already exists, | ||
| 25 | * Success if it was created properly and Failure if there was any error | ||
| 26 | */ | ||
| 27 | bool Initialize(); | ||
| 28 | |||
| 29 | std::string GetName() const override { return "SaveData"; } | ||
| 30 | }; | ||
| 31 | |||
| 32 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index 9d58668e0..dccdf7f67 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp | |||
| @@ -8,8 +8,7 @@ | |||
| 8 | #include "common/file_util.h" | 8 | #include "common/file_util.h" |
| 9 | 9 | ||
| 10 | #include "core/file_sys/archive_sdmc.h" | 10 | #include "core/file_sys/archive_sdmc.h" |
| 11 | #include "core/file_sys/directory_sdmc.h" | 11 | #include "core/file_sys/disk_archive.h" |
| 12 | #include "core/file_sys/file_sdmc.h" | ||
| 13 | #include "core/settings.h" | 12 | #include "core/settings.h" |
| 14 | 13 | ||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -17,18 +16,10 @@ | |||
| 17 | 16 | ||
| 18 | namespace FileSys { | 17 | namespace FileSys { |
| 19 | 18 | ||
| 20 | Archive_SDMC::Archive_SDMC(const std::string& mount_point) { | 19 | Archive_SDMC::Archive_SDMC(const std::string& mount_point) : DiskArchive(mount_point) { |
| 21 | this->mount_point = mount_point; | ||
| 22 | LOG_INFO(Service_FS, "Directory %s set as SDMC.", mount_point.c_str()); | 20 | LOG_INFO(Service_FS, "Directory %s set as SDMC.", mount_point.c_str()); |
| 23 | } | 21 | } |
| 24 | 22 | ||
| 25 | Archive_SDMC::~Archive_SDMC() { | ||
| 26 | } | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Initialize the archive. | ||
| 30 | * @return true if it initialized successfully | ||
| 31 | */ | ||
| 32 | bool Archive_SDMC::Initialize() { | 23 | bool Archive_SDMC::Initialize() { |
| 33 | if (!Settings::values.use_virtual_sd) { | 24 | if (!Settings::values.use_virtual_sd) { |
| 34 | LOG_WARNING(Service_FS, "SDMC disabled by config."); | 25 | LOG_WARNING(Service_FS, "SDMC disabled by config."); |
| @@ -43,74 +34,4 @@ bool Archive_SDMC::Initialize() { | |||
| 43 | return true; | 34 | return true; |
| 44 | } | 35 | } |
| 45 | 36 | ||
| 46 | /** | ||
| 47 | * Open a file specified by its path, using the specified mode | ||
| 48 | * @param path Path relative to the archive | ||
| 49 | * @param mode Mode to open the file with | ||
| 50 | * @return Opened file, or nullptr | ||
| 51 | */ | ||
| 52 | std::unique_ptr<FileBackend> Archive_SDMC::OpenFile(const Path& path, const Mode mode) const { | ||
| 53 | LOG_DEBUG(Service_FS, "called path=%s mode=%u", path.DebugStr().c_str(), mode.hex); | ||
| 54 | File_SDMC* file = new File_SDMC(this, path, mode); | ||
| 55 | if (!file->Open()) | ||
| 56 | return nullptr; | ||
| 57 | return std::unique_ptr<FileBackend>(file); | ||
| 58 | } | ||
| 59 | |||
| 60 | /** | ||
| 61 | * Delete a file specified by its path | ||
| 62 | * @param path Path relative to the archive | ||
| 63 | * @return Whether the file could be deleted | ||
| 64 | */ | ||
| 65 | bool Archive_SDMC::DeleteFile(const FileSys::Path& path) const { | ||
| 66 | return FileUtil::Delete(GetMountPoint() + path.AsString()); | ||
| 67 | } | ||
| 68 | |||
| 69 | bool Archive_SDMC::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const { | ||
| 70 | return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString()); | ||
| 71 | } | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Delete a directory specified by its path | ||
| 75 | * @param path Path relative to the archive | ||
| 76 | * @return Whether the directory could be deleted | ||
| 77 | */ | ||
| 78 | bool Archive_SDMC::DeleteDirectory(const FileSys::Path& path) const { | ||
| 79 | return FileUtil::DeleteDir(GetMountPoint() + path.AsString()); | ||
| 80 | } | ||
| 81 | |||
| 82 | /** | ||
| 83 | * Create a directory specified by its path | ||
| 84 | * @param path Path relative to the archive | ||
| 85 | * @return Whether the directory could be created | ||
| 86 | */ | ||
| 87 | bool Archive_SDMC::CreateDirectory(const Path& path) const { | ||
| 88 | return FileUtil::CreateDir(GetMountPoint() + path.AsString()); | ||
| 89 | } | ||
| 90 | |||
| 91 | bool Archive_SDMC::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const { | ||
| 92 | return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString()); | ||
| 93 | } | ||
| 94 | |||
| 95 | /** | ||
| 96 | * Open a directory specified by its path | ||
| 97 | * @param path Path relative to the archive | ||
| 98 | * @return Opened directory, or nullptr | ||
| 99 | */ | ||
| 100 | std::unique_ptr<DirectoryBackend> Archive_SDMC::OpenDirectory(const Path& path) const { | ||
| 101 | LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str()); | ||
| 102 | Directory_SDMC* directory = new Directory_SDMC(this, path); | ||
| 103 | if (!directory->Open()) | ||
| 104 | return nullptr; | ||
| 105 | return std::unique_ptr<DirectoryBackend>(directory); | ||
| 106 | } | ||
| 107 | |||
| 108 | /** | ||
| 109 | * Getter for the path used for this Archive | ||
| 110 | * @return Mount point of that passthrough archive | ||
| 111 | */ | ||
| 112 | std::string Archive_SDMC::GetMountPoint() const { | ||
| 113 | return mount_point; | ||
| 114 | } | ||
| 115 | |||
| 116 | } // namespace FileSys | 37 | } // namespace FileSys |
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 059045245..c84c6948e 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | 8 | ||
| 9 | #include "core/file_sys/archive_backend.h" | 9 | #include "core/file_sys/disk_archive.h" |
| 10 | #include "core/loader/loader.h" | 10 | #include "core/loader/loader.h" |
| 11 | 11 | ||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -15,10 +15,9 @@ | |||
| 15 | namespace FileSys { | 15 | namespace FileSys { |
| 16 | 16 | ||
| 17 | /// File system interface to the SDMC archive | 17 | /// File system interface to the SDMC archive |
| 18 | class Archive_SDMC final : public ArchiveBackend { | 18 | class Archive_SDMC final : public DiskArchive { |
| 19 | public: | 19 | public: |
| 20 | Archive_SDMC(const std::string& mount_point); | 20 | Archive_SDMC(const std::string& mount_point); |
| 21 | ~Archive_SDMC() override; | ||
| 22 | 21 | ||
| 23 | /** | 22 | /** |
| 24 | * Initialize the archive. | 23 | * Initialize the archive. |
| @@ -27,67 +26,6 @@ public: | |||
| 27 | bool Initialize(); | 26 | bool Initialize(); |
| 28 | 27 | ||
| 29 | std::string GetName() const override { return "SDMC"; } | 28 | std::string GetName() const override { return "SDMC"; } |
| 30 | |||
| 31 | /** | ||
| 32 | * Open a file specified by its path, using the specified mode | ||
| 33 | * @param path Path relative to the archive | ||
| 34 | * @param mode Mode to open the file with | ||
| 35 | * @return Opened file, or nullptr | ||
| 36 | */ | ||
| 37 | std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; | ||
| 38 | |||
| 39 | /** | ||
| 40 | * Delete a file specified by its path | ||
| 41 | * @param path Path relative to the archive | ||
| 42 | * @return Whether the file could be deleted | ||
| 43 | */ | ||
| 44 | bool DeleteFile(const FileSys::Path& path) const override; | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Rename a File specified by its path | ||
| 48 | * @param src_path Source path relative to the archive | ||
| 49 | * @param dest_path Destination path relative to the archive | ||
| 50 | * @return Whether rename succeeded | ||
| 51 | */ | ||
| 52 | bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; | ||
| 53 | |||
| 54 | /** | ||
| 55 | * Delete a directory specified by its path | ||
| 56 | * @param path Path relative to the archive | ||
| 57 | * @return Whether the directory could be deleted | ||
| 58 | */ | ||
| 59 | bool DeleteDirectory(const FileSys::Path& path) const override; | ||
| 60 | |||
| 61 | /** | ||
| 62 | * Create a directory specified by its path | ||
| 63 | * @param path Path relative to the archive | ||
| 64 | * @return Whether the directory could be created | ||
| 65 | */ | ||
| 66 | bool CreateDirectory(const Path& path) const override; | ||
| 67 | |||
| 68 | /** | ||
| 69 | * Rename a Directory specified by its path | ||
| 70 | * @param src_path Source path relative to the archive | ||
| 71 | * @param dest_path Destination path relative to the archive | ||
| 72 | * @return Whether rename succeeded | ||
| 73 | */ | ||
| 74 | bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; | ||
| 75 | |||
| 76 | /** | ||
| 77 | * Open a directory specified by its path | ||
| 78 | * @param path Path relative to the archive | ||
| 79 | * @return Opened directory, or nullptr | ||
| 80 | */ | ||
| 81 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | ||
| 82 | |||
| 83 | /** | ||
| 84 | * Getter for the path used for this Archive | ||
| 85 | * @return Mount point of that passthrough archive | ||
| 86 | */ | ||
| 87 | std::string GetMountPoint() const; | ||
| 88 | |||
| 89 | private: | ||
| 90 | std::string mount_point; | ||
| 91 | }; | 29 | }; |
| 92 | 30 | ||
| 93 | } // namespace FileSys | 31 | } // namespace FileSys |
diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp deleted file mode 100644 index 519787641..000000000 --- a/src/core/file_sys/directory_sdmc.cpp +++ /dev/null | |||
| @@ -1,88 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <sys/stat.h> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | |||
| 10 | #include "core/file_sys/directory_sdmc.h" | ||
| 11 | #include "core/file_sys/archive_sdmc.h" | ||
| 12 | |||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 14 | // FileSys namespace | ||
| 15 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const Path& path) { | ||
| 19 | // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass | ||
| 20 | // the root directory we set while opening the archive. | ||
| 21 | // For example, opening /../../usr/bin can give the emulated program your installed programs. | ||
| 22 | this->path = archive->GetMountPoint() + path.AsString(); | ||
| 23 | |||
| 24 | } | ||
| 25 | |||
| 26 | Directory_SDMC::~Directory_SDMC() { | ||
| 27 | Close(); | ||
| 28 | } | ||
| 29 | |||
| 30 | bool Directory_SDMC::Open() { | ||
| 31 | if (!FileUtil::IsDirectory(path)) | ||
| 32 | return false; | ||
| 33 | FileUtil::ScanDirectoryTree(path, directory); | ||
| 34 | children_iterator = directory.children.begin(); | ||
| 35 | return true; | ||
| 36 | } | ||
| 37 | |||
| 38 | /** | ||
| 39 | * List files contained in the directory | ||
| 40 | * @param count Number of entries to return at once in entries | ||
| 41 | * @param entries Buffer to read data into | ||
| 42 | * @return Number of entries listed | ||
| 43 | */ | ||
| 44 | u32 Directory_SDMC::Read(const u32 count, Entry* entries) { | ||
| 45 | u32 entries_read = 0; | ||
| 46 | |||
| 47 | while (entries_read < count && children_iterator != directory.children.cend()) { | ||
| 48 | const FileUtil::FSTEntry& file = *children_iterator; | ||
| 49 | const std::string& filename = file.virtualName; | ||
| 50 | Entry& entry = entries[entries_read]; | ||
| 51 | |||
| 52 | LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory); | ||
| 53 | |||
| 54 | // TODO(Link Mauve): use a proper conversion to UTF-16. | ||
| 55 | for (size_t j = 0; j < FILENAME_LENGTH; ++j) { | ||
| 56 | entry.filename[j] = filename[j]; | ||
| 57 | if (!filename[j]) | ||
| 58 | break; | ||
| 59 | } | ||
| 60 | |||
| 61 | FileUtil::SplitFilename83(filename, entry.short_name, entry.extension); | ||
| 62 | |||
| 63 | entry.is_directory = file.isDirectory; | ||
| 64 | entry.is_hidden = (filename[0] == '.'); | ||
| 65 | entry.is_read_only = 0; | ||
| 66 | entry.file_size = file.size; | ||
| 67 | |||
| 68 | // We emulate a SD card where the archive bit has never been cleared, as it would be on | ||
| 69 | // most user SD cards. | ||
| 70 | // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a | ||
| 71 | // file bit. | ||
| 72 | entry.is_archive = !file.isDirectory; | ||
| 73 | |||
| 74 | ++entries_read; | ||
| 75 | ++children_iterator; | ||
| 76 | } | ||
| 77 | return entries_read; | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * Close the directory | ||
| 82 | * @return true if the directory closed correctly | ||
| 83 | */ | ||
| 84 | bool Directory_SDMC::Close() const { | ||
| 85 | return true; | ||
| 86 | } | ||
| 87 | |||
| 88 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/directory_sdmc.h b/src/core/file_sys/directory_sdmc.h deleted file mode 100644 index 407a256ef..000000000 --- a/src/core/file_sys/directory_sdmc.h +++ /dev/null | |||
| @@ -1,55 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | |||
| 10 | #include "core/file_sys/directory_backend.h" | ||
| 11 | #include "core/file_sys/archive_sdmc.h" | ||
| 12 | #include "core/loader/loader.h" | ||
| 13 | |||
| 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 15 | // FileSys namespace | ||
| 16 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | class Directory_SDMC final : public DirectoryBackend { | ||
| 20 | public: | ||
| 21 | Directory_SDMC(); | ||
| 22 | Directory_SDMC(const Archive_SDMC* archive, const Path& path); | ||
| 23 | ~Directory_SDMC() override; | ||
| 24 | |||
| 25 | /** | ||
| 26 | * Open the directory | ||
| 27 | * @return true if the directory opened correctly | ||
| 28 | */ | ||
| 29 | bool Open() override; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * List files contained in the directory | ||
| 33 | * @param count Number of entries to return at once in entries | ||
| 34 | * @param entries Buffer to read data into | ||
| 35 | * @return Number of entries listed | ||
| 36 | */ | ||
| 37 | u32 Read(const u32 count, Entry* entries) override; | ||
| 38 | |||
| 39 | /** | ||
| 40 | * Close the directory | ||
| 41 | * @return true if the directory closed correctly | ||
| 42 | */ | ||
| 43 | bool Close() const override; | ||
| 44 | |||
| 45 | private: | ||
| 46 | std::string path; | ||
| 47 | u32 total_entries_in_directory; | ||
| 48 | FileUtil::FSTEntry directory; | ||
| 49 | |||
| 50 | // We need to remember the last entry we returned, so a subsequent call to Read will continue | ||
| 51 | // from the next one. This iterator will always point to the next unread entry. | ||
| 52 | std::vector<FileUtil::FSTEntry>::iterator children_iterator; | ||
| 53 | }; | ||
| 54 | |||
| 55 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp new file mode 100644 index 000000000..eabf58057 --- /dev/null +++ b/src/core/file_sys/disk_archive.cpp | |||
| @@ -0,0 +1,167 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <sys/stat.h> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | |||
| 10 | #include "core/file_sys/disk_archive.h" | ||
| 11 | #include "core/settings.h" | ||
| 12 | |||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 14 | // FileSys namespace | ||
| 15 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | std::unique_ptr<FileBackend> DiskArchive::OpenFile(const Path& path, const Mode mode) const { | ||
| 19 | LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex); | ||
| 20 | DiskFile* file = new DiskFile(this, path, mode); | ||
| 21 | if (!file->Open()) | ||
| 22 | return nullptr; | ||
| 23 | return std::unique_ptr<FileBackend>(file); | ||
| 24 | } | ||
| 25 | |||
| 26 | bool DiskArchive::DeleteFile(const FileSys::Path& path) const { | ||
| 27 | return FileUtil::Delete(GetMountPoint() + path.AsString()); | ||
| 28 | } | ||
| 29 | |||
| 30 | bool DiskArchive::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const { | ||
| 31 | return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString()); | ||
| 32 | } | ||
| 33 | |||
| 34 | bool DiskArchive::DeleteDirectory(const FileSys::Path& path) const { | ||
| 35 | return FileUtil::DeleteDir(GetMountPoint() + path.AsString()); | ||
| 36 | } | ||
| 37 | |||
| 38 | bool DiskArchive::CreateDirectory(const Path& path) const { | ||
| 39 | return FileUtil::CreateDir(GetMountPoint() + path.AsString()); | ||
| 40 | } | ||
| 41 | |||
| 42 | bool DiskArchive::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const { | ||
| 43 | return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString()); | ||
| 44 | } | ||
| 45 | |||
| 46 | std::unique_ptr<DirectoryBackend> DiskArchive::OpenDirectory(const Path& path) const { | ||
| 47 | LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str()); | ||
| 48 | DiskDirectory* directory = new DiskDirectory(this, path); | ||
| 49 | if (!directory->Open()) | ||
| 50 | return nullptr; | ||
| 51 | return std::unique_ptr<DirectoryBackend>(directory); | ||
| 52 | } | ||
| 53 | |||
| 54 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 55 | |||
| 56 | DiskFile::DiskFile(const DiskArchive* archive, const Path& path, const Mode mode) { | ||
| 57 | // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass | ||
| 58 | // the root directory we set while opening the archive. | ||
| 59 | // For example, opening /../../etc/passwd can give the emulated program your users list. | ||
| 60 | this->path = archive->GetMountPoint() + path.AsString(); | ||
| 61 | this->mode.hex = mode.hex; | ||
| 62 | this->archive = archive; | ||
| 63 | } | ||
| 64 | |||
| 65 | bool DiskFile::Open() { | ||
| 66 | if (!mode.create_flag && !FileUtil::Exists(path)) { | ||
| 67 | LOG_ERROR(Service_FS, "Non-existing file %s can’t be open without mode create.", path.c_str()); | ||
| 68 | return false; | ||
| 69 | } | ||
| 70 | |||
| 71 | std::string mode_string; | ||
| 72 | if (mode.create_flag) | ||
| 73 | mode_string = "w+"; | ||
| 74 | else if (mode.write_flag) | ||
| 75 | mode_string = "r+"; // Files opened with Write access can be read from | ||
| 76 | else if (mode.read_flag) | ||
| 77 | mode_string = "r"; | ||
| 78 | |||
| 79 | // Open the file in binary mode, to avoid problems with CR/LF on Windows systems | ||
| 80 | mode_string += "b"; | ||
| 81 | |||
| 82 | file = new FileUtil::IOFile(path, mode_string.c_str()); | ||
| 83 | return true; | ||
| 84 | } | ||
| 85 | |||
| 86 | size_t DiskFile::Read(const u64 offset, const u32 length, u8* buffer) const { | ||
| 87 | file->Seek(offset, SEEK_SET); | ||
| 88 | return file->ReadBytes(buffer, length); | ||
| 89 | } | ||
| 90 | |||
| 91 | size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { | ||
| 92 | file->Seek(offset, SEEK_SET); | ||
| 93 | size_t written = file->WriteBytes(buffer, length); | ||
| 94 | if (flush) | ||
| 95 | file->Flush(); | ||
| 96 | return written; | ||
| 97 | } | ||
| 98 | |||
| 99 | size_t DiskFile::GetSize() const { | ||
| 100 | return static_cast<size_t>(file->GetSize()); | ||
| 101 | } | ||
| 102 | |||
| 103 | bool DiskFile::SetSize(const u64 size) const { | ||
| 104 | file->Resize(size); | ||
| 105 | file->Flush(); | ||
| 106 | return true; | ||
| 107 | } | ||
| 108 | |||
| 109 | bool DiskFile::Close() const { | ||
| 110 | return file->Close(); | ||
| 111 | } | ||
| 112 | |||
| 113 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 114 | |||
| 115 | DiskDirectory::DiskDirectory(const DiskArchive* archive, const Path& path) { | ||
| 116 | // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass | ||
| 117 | // the root directory we set while opening the archive. | ||
| 118 | // For example, opening /../../usr/bin can give the emulated program your installed programs. | ||
| 119 | this->path = archive->GetMountPoint() + path.AsString(); | ||
| 120 | this->archive = archive; | ||
| 121 | } | ||
| 122 | |||
| 123 | bool DiskDirectory::Open() { | ||
| 124 | if (!FileUtil::IsDirectory(path)) | ||
| 125 | return false; | ||
| 126 | FileUtil::ScanDirectoryTree(path, directory); | ||
| 127 | children_iterator = directory.children.begin(); | ||
| 128 | return true; | ||
| 129 | } | ||
| 130 | |||
| 131 | u32 DiskDirectory::Read(const u32 count, Entry* entries) { | ||
| 132 | u32 entries_read = 0; | ||
| 133 | |||
| 134 | while (entries_read < count && children_iterator != directory.children.cend()) { | ||
| 135 | const FileUtil::FSTEntry& file = *children_iterator; | ||
| 136 | const std::string& filename = file.virtualName; | ||
| 137 | Entry& entry = entries[entries_read]; | ||
| 138 | |||
| 139 | LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory); | ||
| 140 | |||
| 141 | // TODO(Link Mauve): use a proper conversion to UTF-16. | ||
| 142 | for (size_t j = 0; j < FILENAME_LENGTH; ++j) { | ||
| 143 | entry.filename[j] = filename[j]; | ||
| 144 | if (!filename[j]) | ||
| 145 | break; | ||
| 146 | } | ||
| 147 | |||
| 148 | FileUtil::SplitFilename83(filename, entry.short_name, entry.extension); | ||
| 149 | |||
| 150 | entry.is_directory = file.isDirectory; | ||
| 151 | entry.is_hidden = (filename[0] == '.'); | ||
| 152 | entry.is_read_only = 0; | ||
| 153 | entry.file_size = file.size; | ||
| 154 | |||
| 155 | // We emulate a SD card where the archive bit has never been cleared, as it would be on | ||
| 156 | // most user SD cards. | ||
| 157 | // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a | ||
| 158 | // file bit. | ||
| 159 | entry.is_archive = !file.isDirectory; | ||
| 160 | |||
| 161 | ++entries_read; | ||
| 162 | ++children_iterator; | ||
| 163 | } | ||
| 164 | return entries_read; | ||
| 165 | } | ||
| 166 | |||
| 167 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h new file mode 100644 index 000000000..778c83953 --- /dev/null +++ b/src/core/file_sys/disk_archive.h | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | #include "core/file_sys/archive_backend.h" | ||
| 10 | #include "core/loader/loader.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // FileSys namespace | ||
| 14 | |||
| 15 | namespace FileSys { | ||
| 16 | |||
| 17 | /** | ||
| 18 | * Helper which implements a backend accessing the host machine's filesystem. | ||
| 19 | * This should be subclassed by concrete archive types, which will provide the | ||
| 20 | * base directory on the host filesystem and override any required functionality. | ||
| 21 | */ | ||
| 22 | class DiskArchive : public ArchiveBackend { | ||
| 23 | public: | ||
| 24 | DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {} | ||
| 25 | |||
| 26 | virtual std::string GetName() const = 0; | ||
| 27 | std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; | ||
| 28 | bool DeleteFile(const FileSys::Path& path) const override; | ||
| 29 | bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; | ||
| 30 | bool DeleteDirectory(const FileSys::Path& path) const override; | ||
| 31 | bool CreateDirectory(const Path& path) const override; | ||
| 32 | bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override; | ||
| 33 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * Getter for the path used for this Archive | ||
| 37 | * @return Mount point of that passthrough archive | ||
| 38 | */ | ||
| 39 | const std::string& GetMountPoint() const { | ||
| 40 | return mount_point; | ||
| 41 | } | ||
| 42 | |||
| 43 | protected: | ||
| 44 | std::string mount_point; | ||
| 45 | }; | ||
| 46 | |||
| 47 | class DiskFile : public FileBackend { | ||
| 48 | public: | ||
| 49 | DiskFile(); | ||
| 50 | DiskFile(const DiskArchive* archive, const Path& path, const Mode mode); | ||
| 51 | |||
| 52 | ~DiskFile() override { | ||
| 53 | Close(); | ||
| 54 | } | ||
| 55 | |||
| 56 | bool Open() override; | ||
| 57 | size_t Read(const u64 offset, const u32 length, u8* buffer) const override; | ||
| 58 | size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; | ||
| 59 | size_t GetSize() const override; | ||
| 60 | bool SetSize(const u64 size) const override; | ||
| 61 | bool Close() const override; | ||
| 62 | |||
| 63 | void Flush() const override { | ||
| 64 | file->Flush(); | ||
| 65 | } | ||
| 66 | |||
| 67 | protected: | ||
| 68 | const DiskArchive* archive; | ||
| 69 | std::string path; | ||
| 70 | Mode mode; | ||
| 71 | FileUtil::IOFile* file; | ||
| 72 | }; | ||
| 73 | |||
| 74 | class DiskDirectory : public DirectoryBackend { | ||
| 75 | public: | ||
| 76 | DiskDirectory(); | ||
| 77 | DiskDirectory(const DiskArchive* archive, const Path& path); | ||
| 78 | |||
| 79 | ~DiskDirectory() override { | ||
| 80 | Close(); | ||
| 81 | } | ||
| 82 | |||
| 83 | bool Open() override; | ||
| 84 | u32 Read(const u32 count, Entry* entries) override; | ||
| 85 | |||
| 86 | bool Close() const override { | ||
| 87 | return true; | ||
| 88 | } | ||
| 89 | |||
| 90 | protected: | ||
| 91 | const DiskArchive* archive; | ||
| 92 | std::string path; | ||
| 93 | u32 total_entries_in_directory; | ||
| 94 | FileUtil::FSTEntry directory; | ||
| 95 | |||
| 96 | // We need to remember the last entry we returned, so a subsequent call to Read will continue | ||
| 97 | // from the next one. This iterator will always point to the next unread entry. | ||
| 98 | std::vector<FileUtil::FSTEntry>::iterator children_iterator; | ||
| 99 | }; | ||
| 100 | |||
| 101 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h index 1b81d5fe9..539ec7314 100644 --- a/src/core/file_sys/file_backend.h +++ b/src/core/file_sys/file_backend.h | |||
| @@ -61,6 +61,11 @@ public: | |||
| 61 | * @return true if the file closed correctly | 61 | * @return true if the file closed correctly |
| 62 | */ | 62 | */ |
| 63 | virtual bool Close() const = 0; | 63 | virtual bool Close() const = 0; |
| 64 | |||
| 65 | /** | ||
| 66 | * Flushes the file | ||
| 67 | */ | ||
| 68 | virtual void Flush() const = 0; | ||
| 64 | }; | 69 | }; |
| 65 | 70 | ||
| 66 | } // namespace FileSys | 71 | } // namespace FileSys |
diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h index 09fa2e7e3..32fa6b6d3 100644 --- a/src/core/file_sys/file_romfs.h +++ b/src/core/file_sys/file_romfs.h | |||
| @@ -64,6 +64,8 @@ public: | |||
| 64 | */ | 64 | */ |
| 65 | bool Close() const override; | 65 | bool Close() const override; |
| 66 | 66 | ||
| 67 | void Flush() const override { } | ||
| 68 | |||
| 67 | private: | 69 | private: |
| 68 | const Archive_RomFS* archive; | 70 | const Archive_RomFS* archive; |
| 69 | }; | 71 | }; |
diff --git a/src/core/file_sys/file_sdmc.cpp b/src/core/file_sys/file_sdmc.cpp deleted file mode 100644 index 46c29900b..000000000 --- a/src/core/file_sys/file_sdmc.cpp +++ /dev/null | |||
| @@ -1,110 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <sys/stat.h> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | |||
| 10 | #include "core/file_sys/file_sdmc.h" | ||
| 11 | #include "core/file_sys/archive_sdmc.h" | ||
| 12 | |||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 14 | // FileSys namespace | ||
| 15 | |||
| 16 | namespace FileSys { | ||
| 17 | |||
| 18 | File_SDMC::File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode) { | ||
| 19 | // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass | ||
| 20 | // the root directory we set while opening the archive. | ||
| 21 | // For example, opening /../../etc/passwd can give the emulated program your users list. | ||
| 22 | this->path = archive->GetMountPoint() + path.AsString(); | ||
| 23 | this->mode.hex = mode.hex; | ||
| 24 | } | ||
| 25 | |||
| 26 | File_SDMC::~File_SDMC() { | ||
| 27 | Close(); | ||
| 28 | } | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Open the file | ||
| 32 | * @return true if the file opened correctly | ||
| 33 | */ | ||
| 34 | bool File_SDMC::Open() { | ||
| 35 | if (!mode.create_flag && !FileUtil::Exists(path)) { | ||
| 36 | LOG_ERROR(Service_FS, "Non-existing file %s can’t be open without mode create.", path.c_str()); | ||
| 37 | return false; | ||
| 38 | } | ||
| 39 | |||
| 40 | std::string mode_string; | ||
| 41 | if (mode.create_flag) | ||
| 42 | mode_string = "w+"; | ||
| 43 | else if (mode.write_flag) | ||
| 44 | mode_string = "r+"; // Files opened with Write access can be read from | ||
| 45 | else if (mode.read_flag) | ||
| 46 | mode_string = "r"; | ||
| 47 | |||
| 48 | // Open the file in binary mode, to avoid problems with CR/LF on Windows systems | ||
| 49 | mode_string += "b"; | ||
| 50 | |||
| 51 | file = new FileUtil::IOFile(path, mode_string.c_str()); | ||
| 52 | return true; | ||
| 53 | } | ||
| 54 | |||
| 55 | /** | ||
| 56 | * Read data from the file | ||
| 57 | * @param offset Offset in bytes to start reading data from | ||
| 58 | * @param length Length in bytes of data to read from file | ||
| 59 | * @param buffer Buffer to read data into | ||
| 60 | * @return Number of bytes read | ||
| 61 | */ | ||
| 62 | size_t File_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const { | ||
| 63 | file->Seek(offset, SEEK_SET); | ||
| 64 | return file->ReadBytes(buffer, length); | ||
| 65 | } | ||
| 66 | |||
| 67 | /** | ||
| 68 | * Write data to the file | ||
| 69 | * @param offset Offset in bytes to start writing data to | ||
| 70 | * @param length Length in bytes of data to write to file | ||
| 71 | * @param flush The flush parameters (0 == do not flush) | ||
| 72 | * @param buffer Buffer to read data from | ||
| 73 | * @return Number of bytes written | ||
| 74 | */ | ||
| 75 | size_t File_SDMC::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { | ||
| 76 | file->Seek(offset, SEEK_SET); | ||
| 77 | size_t written = file->WriteBytes(buffer, length); | ||
| 78 | if (flush) | ||
| 79 | file->Flush(); | ||
| 80 | return written; | ||
| 81 | } | ||
| 82 | |||
| 83 | /** | ||
| 84 | * Get the size of the file in bytes | ||
| 85 | * @return Size of the file in bytes | ||
| 86 | */ | ||
| 87 | size_t File_SDMC::GetSize() const { | ||
| 88 | return static_cast<size_t>(file->GetSize()); | ||
| 89 | } | ||
| 90 | |||
| 91 | /** | ||
| 92 | * Set the size of the file in bytes | ||
| 93 | * @param size New size of the file | ||
| 94 | * @return true if successful | ||
| 95 | */ | ||
| 96 | bool File_SDMC::SetSize(const u64 size) const { | ||
| 97 | file->Resize(size); | ||
| 98 | file->Flush(); | ||
| 99 | return true; | ||
| 100 | } | ||
| 101 | |||
| 102 | /** | ||
| 103 | * Close the file | ||
| 104 | * @return true if the file closed correctly | ||
| 105 | */ | ||
| 106 | bool File_SDMC::Close() const { | ||
| 107 | return file->Close(); | ||
| 108 | } | ||
| 109 | |||
| 110 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/file_sdmc.h b/src/core/file_sys/file_sdmc.h deleted file mode 100644 index e01548598..000000000 --- a/src/core/file_sys/file_sdmc.h +++ /dev/null | |||
| @@ -1,75 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | |||
| 10 | #include "core/file_sys/file_backend.h" | ||
| 11 | #include "core/file_sys/archive_sdmc.h" | ||
| 12 | #include "core/loader/loader.h" | ||
| 13 | |||
| 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 15 | // FileSys namespace | ||
| 16 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | class File_SDMC final : public FileBackend { | ||
| 20 | public: | ||
| 21 | File_SDMC(); | ||
| 22 | File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode); | ||
| 23 | ~File_SDMC() override; | ||
| 24 | |||
| 25 | /** | ||
| 26 | * Open the file | ||
| 27 | * @return true if the file opened correctly | ||
| 28 | */ | ||
| 29 | bool Open() override; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Read data from the file | ||
| 33 | * @param offset Offset in bytes to start reading data from | ||
| 34 | * @param length Length in bytes of data to read from file | ||
| 35 | * @param buffer Buffer to read data into | ||
| 36 | * @return Number of bytes read | ||
| 37 | */ | ||
| 38 | size_t Read(const u64 offset, const u32 length, u8* buffer) const override; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * Write data to the file | ||
| 42 | * @param offset Offset in bytes to start writing data to | ||
| 43 | * @param length Length in bytes of data to write to file | ||
| 44 | * @param flush The flush parameters (0 == do not flush) | ||
| 45 | * @param buffer Buffer to read data from | ||
| 46 | * @return Number of bytes written | ||
| 47 | */ | ||
| 48 | size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; | ||
| 49 | |||
| 50 | /** | ||
| 51 | * Get the size of the file in bytes | ||
| 52 | * @return Size of the file in bytes | ||
| 53 | */ | ||
| 54 | size_t GetSize() const override; | ||
| 55 | |||
| 56 | /** | ||
| 57 | * Set the size of the file in bytes | ||
| 58 | * @param size New size of the file | ||
| 59 | * @return true if successful | ||
| 60 | */ | ||
| 61 | bool SetSize(const u64 size) const override; | ||
| 62 | |||
| 63 | /** | ||
| 64 | * Close the file | ||
| 65 | * @return true if the file closed correctly | ||
| 66 | */ | ||
| 67 | bool Close() const override; | ||
| 68 | |||
| 69 | private: | ||
| 70 | std::string path; | ||
| 71 | Mode mode; | ||
| 72 | FileUtil::IOFile* file; | ||
| 73 | }; | ||
| 74 | |||
| 75 | } // namespace FileSys | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 929422b36..6a690e915 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -14,6 +14,7 @@ namespace Kernel { | |||
| 14 | 14 | ||
| 15 | Handle g_main_thread = 0; | 15 | Handle g_main_thread = 0; |
| 16 | ObjectPool g_object_pool; | 16 | ObjectPool g_object_pool; |
| 17 | u64 g_program_id = 0; | ||
| 17 | 18 | ||
| 18 | ObjectPool::ObjectPool() { | 19 | ObjectPool::ObjectPool() { |
| 19 | next_id = INITIAL_NEXT_ID; | 20 | next_id = INITIAL_NEXT_ID; |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 7e0f15c84..7123485be 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -151,6 +151,12 @@ private: | |||
| 151 | extern ObjectPool g_object_pool; | 151 | extern ObjectPool g_object_pool; |
| 152 | extern Handle g_main_thread; | 152 | extern Handle g_main_thread; |
| 153 | 153 | ||
| 154 | /// The ID code of the currently running game | ||
| 155 | /// TODO(Subv): This variable should not be here, | ||
| 156 | /// we need a way to store information about the currently loaded application | ||
| 157 | /// for later query during runtime, maybe using the LDR service? | ||
| 158 | extern u64 g_program_id; | ||
| 159 | |||
| 154 | /// Initialize the kernel | 160 | /// Initialize the kernel |
| 155 | void Init(); | 161 | void Init(); |
| 156 | 162 | ||
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 304cf5b67..bb778ec26 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h | |||
| @@ -12,11 +12,15 @@ namespace Kernel { | |||
| 12 | 12 | ||
| 13 | /// Permissions for mapped shared memory blocks | 13 | /// Permissions for mapped shared memory blocks |
| 14 | enum class MemoryPermission : u32 { | 14 | enum class MemoryPermission : u32 { |
| 15 | None = 0, | 15 | None = 0, |
| 16 | Read = (1u << 0), | 16 | Read = (1u << 0), |
| 17 | Write = (1u << 1), | 17 | Write = (1u << 1), |
| 18 | ReadWrite = (Read | Write), | 18 | ReadWrite = (Read | Write), |
| 19 | DontCare = (1u << 28) | 19 | Execute = (1u << 2), |
| 20 | ReadExecute = (Read | Execute), | ||
| 21 | WriteExecute = (Write | Execute), | ||
| 22 | ReadWriteExecute = (Read | Write | Execute), | ||
| 23 | DontCare = (1u << 28) | ||
| 20 | }; | 24 | }; |
| 21 | 25 | ||
| 22 | /** | 26 | /** |
diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 15c4a2677..14d2be4a2 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | /// Detailed description of the error. This listing is likely incomplete. | 17 | /// Detailed description of the error. This listing is likely incomplete. |
| 18 | enum class ErrorDescription : u32 { | 18 | enum class ErrorDescription : u32 { |
| 19 | Success = 0, | 19 | Success = 0, |
| 20 | FS_NotFound = 100, | ||
| 21 | FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive | ||
| 20 | InvalidSection = 1000, | 22 | InvalidSection = 1000, |
| 21 | TooLarge = 1001, | 23 | TooLarge = 1001, |
| 22 | NotAuthorized = 1002, | 24 | NotAuthorized = 1002, |
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index caf82d556..9c3834733 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| 10 | #include "common/math_util.h" | 10 | #include "common/math_util.h" |
| 11 | 11 | ||
| 12 | #include "core/file_sys/archive_savedata.h" | ||
| 12 | #include "core/file_sys/archive_backend.h" | 13 | #include "core/file_sys/archive_backend.h" |
| 13 | #include "core/file_sys/archive_sdmc.h" | 14 | #include "core/file_sys/archive_sdmc.h" |
| 14 | #include "core/file_sys/directory_backend.h" | 15 | #include "core/file_sys/directory_backend.h" |
| @@ -135,6 +136,13 @@ public: | |||
| 135 | break; | 136 | break; |
| 136 | } | 137 | } |
| 137 | 138 | ||
| 139 | case FileCommand::Flush: | ||
| 140 | { | ||
| 141 | LOG_TRACE(Service_FS, "Flush"); | ||
| 142 | backend->Flush(); | ||
| 143 | break; | ||
| 144 | } | ||
| 145 | |||
| 138 | // Unknown command... | 146 | // Unknown command... |
| 139 | default: | 147 | default: |
| 140 | LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); | 148 | LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); |
| @@ -220,9 +228,18 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code) { | |||
| 220 | 228 | ||
| 221 | auto itr = id_code_map.find(id_code); | 229 | auto itr = id_code_map.find(id_code); |
| 222 | if (itr == id_code_map.end()) { | 230 | if (itr == id_code_map.end()) { |
| 231 | if (id_code == ArchiveIdCode::SaveData) { | ||
| 232 | // When a SaveData archive is created for the first time, it is not yet formatted | ||
| 233 | // and the save file/directory structure expected by the game has not yet been initialized. | ||
| 234 | // Returning the NotFormatted error code will signal the game to provision the SaveData archive | ||
| 235 | // with the files and folders that it expects. | ||
| 236 | // The FormatSaveData service call will create the SaveData archive when it is called. | ||
| 237 | return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, | ||
| 238 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 239 | } | ||
| 223 | // TODO: Verify error against hardware | 240 | // TODO: Verify error against hardware |
| 224 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | 241 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, |
| 225 | ErrorSummary::NotFound, ErrorLevel::Permanent); | 242 | ErrorSummary::NotFound, ErrorLevel::Permanent); |
| 226 | } | 243 | } |
| 227 | 244 | ||
| 228 | // This should never even happen in the first place with 64-bit handles, | 245 | // This should never even happen in the first place with 64-bit handles, |
| @@ -260,8 +277,8 @@ ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSy | |||
| 260 | 277 | ||
| 261 | std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); | 278 | std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); |
| 262 | if (backend == nullptr) { | 279 | if (backend == nullptr) { |
| 263 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | 280 | return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, |
| 264 | ErrorSummary::NotFound, ErrorLevel::Permanent); | 281 | ErrorSummary::NotFound, ErrorLevel::Status); |
| 265 | } | 282 | } |
| 266 | 283 | ||
| 267 | auto file = std::make_unique<File>(std::move(backend), path); | 284 | auto file = std::make_unique<File>(std::move(backend), path); |
| @@ -366,6 +383,28 @@ ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const F | |||
| 366 | return MakeResult<Handle>(handle); | 383 | return MakeResult<Handle>(handle); |
| 367 | } | 384 | } |
| 368 | 385 | ||
| 386 | ResultCode FormatSaveData() { | ||
| 387 | // TODO(Subv): Actually wipe the savedata folder after creating or opening it | ||
| 388 | |||
| 389 | // Do not create the archive again if it already exists | ||
| 390 | if (id_code_map.find(ArchiveIdCode::SaveData) != id_code_map.end()) | ||
| 391 | return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the correct error code | ||
| 392 | |||
| 393 | // Create the SaveData archive | ||
| 394 | std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX); | ||
| 395 | auto savedata_archive = std::make_unique<FileSys::Archive_SaveData>(savedata_directory, | ||
| 396 | Kernel::g_program_id); | ||
| 397 | |||
| 398 | if (savedata_archive->Initialize()) { | ||
| 399 | CreateArchive(std::move(savedata_archive), ArchiveIdCode::SaveData); | ||
| 400 | return RESULT_SUCCESS; | ||
| 401 | } else { | ||
| 402 | LOG_ERROR(Service_FS, "Can't instantiate SaveData archive with path %s", | ||
| 403 | savedata_archive->GetMountPoint().c_str()); | ||
| 404 | return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the proper error code | ||
| 405 | } | ||
| 406 | } | ||
| 407 | |||
| 369 | /// Initialize archives | 408 | /// Initialize archives |
| 370 | void ArchiveInit() { | 409 | void ArchiveInit() { |
| 371 | next_handle = 1; | 410 | next_handle = 1; |
| @@ -375,9 +414,9 @@ void ArchiveInit() { | |||
| 375 | // archive type is SDMC, so it is the only one getting exposed. | 414 | // archive type is SDMC, so it is the only one getting exposed. |
| 376 | 415 | ||
| 377 | std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); | 416 | std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); |
| 378 | auto archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory); | 417 | auto sdmc_archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory); |
| 379 | if (archive->Initialize()) | 418 | if (sdmc_archive->Initialize()) |
| 380 | CreateArchive(std::move(archive), ArchiveIdCode::SDMC); | 419 | CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC); |
| 381 | else | 420 | else |
| 382 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); | 421 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); |
| 383 | } | 422 | } |
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index a38de92e3..a128276b6 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h | |||
| @@ -109,6 +109,12 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons | |||
| 109 | */ | 109 | */ |
| 110 | ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); | 110 | ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); |
| 111 | 111 | ||
| 112 | /** | ||
| 113 | * Creates a blank SaveData archive. | ||
| 114 | * @return ResultCode 0 on success or the corresponding code on error | ||
| 115 | */ | ||
| 116 | ResultCode FormatSaveData(); | ||
| 117 | |||
| 112 | /// Initialize archives | 118 | /// Initialize archives |
| 113 | void ArchiveInit(); | 119 | void ArchiveInit(); |
| 114 | 120 | ||
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 0f75d5e3a..f99d84b2f 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp | |||
| @@ -3,11 +3,11 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/common.h" | 5 | #include "common/common.h" |
| 6 | #include "common/file_util.h" | ||
| 6 | #include "common/scope_exit.h" | 7 | #include "common/scope_exit.h" |
| 7 | |||
| 8 | #include "common/string_util.h" | 8 | #include "common/string_util.h" |
| 9 | #include "core/hle/service/fs/archive.h" | ||
| 10 | #include "core/hle/result.h" | 9 | #include "core/hle/result.h" |
| 10 | #include "core/hle/service/fs/archive.h" | ||
| 11 | #include "core/hle/service/fs/fs_user.h" | 11 | #include "core/hle/service/fs/fs_user.h" |
| 12 | #include "core/settings.h" | 12 | #include "core/settings.h" |
| 13 | 13 | ||
| @@ -50,9 +50,7 @@ static void Initialize(Service::Interface* self) { | |||
| 50 | static void OpenFile(Service::Interface* self) { | 50 | static void OpenFile(Service::Interface* self) { |
| 51 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 51 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 52 | 52 | ||
| 53 | // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to | 53 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); |
| 54 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 55 | Handle archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 56 | auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | 54 | auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); |
| 57 | u32 filename_size = cmd_buff[5]; | 55 | u32 filename_size = cmd_buff[5]; |
| 58 | FileSys::Mode mode; mode.hex = cmd_buff[6]; | 56 | FileSys::Mode mode; mode.hex = cmd_buff[6]; |
| @@ -398,6 +396,36 @@ static void IsSdmcDetected(Service::Interface* self) { | |||
| 398 | LOG_DEBUG(Service_FS, "called"); | 396 | LOG_DEBUG(Service_FS, "called"); |
| 399 | } | 397 | } |
| 400 | 398 | ||
| 399 | /** | ||
| 400 | * FS_User::FormatSaveData service function | ||
| 401 | * Inputs: | ||
| 402 | * Outputs: | ||
| 403 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 404 | */ | ||
| 405 | static void FormatSaveData(Service::Interface* self) { | ||
| 406 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 407 | LOG_DEBUG(Service_FS, "(STUBBED)"); | ||
| 408 | |||
| 409 | // TODO(Subv): Find out what the inputs and outputs of this function are | ||
| 410 | |||
| 411 | cmd_buff[1] = FormatSaveData().raw; | ||
| 412 | } | ||
| 413 | |||
| 414 | /** | ||
| 415 | * FS_User::FormatThisUserSaveData service function | ||
| 416 | * Inputs: | ||
| 417 | * Outputs: | ||
| 418 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 419 | */ | ||
| 420 | static void FormatThisUserSaveData(Service::Interface* self) { | ||
| 421 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 422 | LOG_DEBUG(Service_FS, "(STUBBED)"); | ||
| 423 | |||
| 424 | // TODO(Subv): Find out what the inputs and outputs of this function are | ||
| 425 | |||
| 426 | cmd_buff[1] = FormatSaveData().raw; | ||
| 427 | } | ||
| 428 | |||
| 401 | const FSUserInterface::FunctionInfo FunctionTable[] = { | 429 | const FSUserInterface::FunctionInfo FunctionTable[] = { |
| 402 | {0x000100C6, nullptr, "Dummy1"}, | 430 | {0x000100C6, nullptr, "Dummy1"}, |
| 403 | {0x040100C4, nullptr, "Control"}, | 431 | {0x040100C4, nullptr, "Control"}, |
| @@ -415,7 +443,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = { | |||
| 415 | {0x080C00C2, OpenArchive, "OpenArchive"}, | 443 | {0x080C00C2, OpenArchive, "OpenArchive"}, |
| 416 | {0x080D0144, nullptr, "ControlArchive"}, | 444 | {0x080D0144, nullptr, "ControlArchive"}, |
| 417 | {0x080E0080, CloseArchive, "CloseArchive"}, | 445 | {0x080E0080, CloseArchive, "CloseArchive"}, |
| 418 | {0x080F0180, nullptr, "FormatThisUserSaveData"}, | 446 | {0x080F0180, FormatThisUserSaveData,"FormatThisUserSaveData"}, |
| 419 | {0x08100200, nullptr, "CreateSystemSaveData"}, | 447 | {0x08100200, nullptr, "CreateSystemSaveData"}, |
| 420 | {0x08110040, nullptr, "DeleteSystemSaveData"}, | 448 | {0x08110040, nullptr, "DeleteSystemSaveData"}, |
| 421 | {0x08120080, nullptr, "GetFreeBytes"}, | 449 | {0x08120080, nullptr, "GetFreeBytes"}, |
| @@ -476,7 +504,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = { | |||
| 476 | {0x08490040, nullptr, "GetArchiveResource"}, | 504 | {0x08490040, nullptr, "GetArchiveResource"}, |
| 477 | {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"}, | 505 | {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"}, |
| 478 | {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"}, | 506 | {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"}, |
| 479 | {0x084C0242, nullptr, "FormatSaveData"}, | 507 | {0x084C0242, FormatSaveData, "FormatSaveData"}, |
| 480 | {0x084D0102, nullptr, "GetLegacySubBannerData"}, | 508 | {0x084D0102, nullptr, "GetLegacySubBannerData"}, |
| 481 | {0x084E0342, nullptr, "UpdateSha256Context"}, | 509 | {0x084E0342, nullptr, "UpdateSha256Context"}, |
| 482 | {0x084F0102, nullptr, "ReadSpecialFile"}, | 510 | {0x084F0102, nullptr, "ReadSpecialFile"}, |
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 15cc240f4..47e9bf77e 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -64,6 +64,10 @@ static Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other | |||
| 64 | case Kernel::MemoryPermission::Read: | 64 | case Kernel::MemoryPermission::Read: |
| 65 | case Kernel::MemoryPermission::Write: | 65 | case Kernel::MemoryPermission::Write: |
| 66 | case Kernel::MemoryPermission::ReadWrite: | 66 | case Kernel::MemoryPermission::ReadWrite: |
| 67 | case Kernel::MemoryPermission::Execute: | ||
| 68 | case Kernel::MemoryPermission::ReadExecute: | ||
| 69 | case Kernel::MemoryPermission::WriteExecute: | ||
| 70 | case Kernel::MemoryPermission::ReadWriteExecute: | ||
| 67 | case Kernel::MemoryPermission::DontCare: | 71 | case Kernel::MemoryPermission::DontCare: |
| 68 | Kernel::MapSharedMemory(handle, addr, permissions_type, | 72 | Kernel::MapSharedMemory(handle, addr, permissions_type, |
| 69 | static_cast<Kernel::MemoryPermission>(other_permissions)); | 73 | static_cast<Kernel::MemoryPermission>(other_permissions)); |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 463dacca3..480274d23 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -74,6 +74,7 @@ ResultStatus LoadFile(const std::string& filename) { | |||
| 74 | 74 | ||
| 75 | // Load application and RomFS | 75 | // Load application and RomFS |
| 76 | if (ResultStatus::Success == app_loader.Load()) { | 76 | if (ResultStatus::Success == app_loader.Load()) { |
| 77 | Kernel::g_program_id = app_loader.GetProgramId(); | ||
| 77 | Service::FS::CreateArchive(std::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS); | 78 | Service::FS::CreateArchive(std::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS); |
| 78 | return ResultStatus::Success; | 79 | return ResultStatus::Success; |
| 79 | } | 80 | } |
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index ba9ba00c0..4d23656ec 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp | |||
| @@ -315,4 +315,8 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const { | |||
| 315 | return ResultStatus::Error; | 315 | return ResultStatus::Error; |
| 316 | } | 316 | } |
| 317 | 317 | ||
| 318 | u64 AppLoader_NCCH::GetProgramId() const { | ||
| 319 | return *reinterpret_cast<u64 const*>(&ncch_header.program_id[0]); | ||
| 320 | } | ||
| 321 | |||
| 318 | } // namespace Loader | 322 | } // namespace Loader |
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h index 03116add8..2fe2a7d82 100644 --- a/src/core/loader/ncch.h +++ b/src/core/loader/ncch.h | |||
| @@ -191,6 +191,12 @@ public: | |||
| 191 | */ | 191 | */ |
| 192 | ResultStatus ReadRomFS(std::vector<u8>& buffer) const override; | 192 | ResultStatus ReadRomFS(std::vector<u8>& buffer) const override; |
| 193 | 193 | ||
| 194 | /* | ||
| 195 | * Gets the program id from the NCCH header | ||
| 196 | * @return u64 Program id | ||
| 197 | */ | ||
| 198 | u64 GetProgramId() const; | ||
| 199 | |||
| 194 | private: | 200 | private: |
| 195 | 201 | ||
| 196 | /** | 202 | /** |