Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0a66a63ba | ||
|
|
0d840e199d | ||
|
|
3a2bceef8d | ||
|
|
e871a754a8 | ||
|
|
6333327b81 | ||
|
|
18ca8aaf5b | ||
|
|
67c0f4527e | ||
|
|
e5c5101e8a | ||
|
|
934ff7bbde | ||
|
|
014f08f6b4 | ||
|
|
6ba2090c01 | ||
|
|
61fcf5e0f4 | ||
|
|
9217e4c5f9 | ||
|
|
3ccbb34c62 | ||
|
|
9baa4a17ed | ||
|
|
6bbece39bc | ||
|
|
729447eab0 | ||
|
|
1e7f41ea9f | ||
|
|
d0d4888184 | ||
|
|
804e5d49bb | ||
|
|
6d1d226842 | ||
|
|
06416aeded | ||
|
|
4fbae9e5a4 | ||
|
|
c87be7cd69 | ||
|
|
e62754ed56 | ||
|
|
53d7281e66 | ||
|
|
731a2c11a4 | ||
|
|
ec4d078d6d | ||
|
|
f9b48f06a3 | ||
|
|
d986ffa153 | ||
|
|
2357bc70a7 | ||
|
|
e86e1588e3 | ||
|
|
4be88c7180 | ||
|
|
8e8daa64ba | ||
|
|
1671c04e24 | ||
|
|
d3d6c552b7 | ||
|
|
8d9336f561 | ||
|
|
169ec9c12e | ||
|
|
60b831f369 | ||
|
|
4191dcee75 | ||
|
|
44725c8910 | ||
|
|
cead8a36ea | ||
|
|
7b6050a0cb | ||
|
|
491383c637 | ||
|
|
d7a3645f7f | ||
|
|
241b8f4627 |
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
|
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MINOR 9
|
#define ATMOSPHERE_RELEASE_VERSION_MINOR 9
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 1
|
#define ATMOSPHERE_RELEASE_VERSION_MICRO 2
|
||||||
|
|
||||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 8
|
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 8
|
||||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1
|
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1
|
||||||
|
|||||||
@@ -1,4 +1,27 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
## 0.9.2
|
||||||
|
+ A number of emummc bugfixes were added (all thanks to @m4xw's hard work). The following is a summary of emummc changes:
|
||||||
|
+ Support for file-based emummc instances was fixed.
|
||||||
|
+ Please note: file-based emummc is still unoptimized, and so may be much slower than partition-based.
|
||||||
|
+ This speed differential should hopefully be made better in a future emummc update.
|
||||||
|
+ The way emummc handles power management was completely overhauled.
|
||||||
|
+ Emummc now properly handles init/de-init, and now supports low voltage mode.
|
||||||
|
+ Much better support for shutdown was added, which should assuage corruption/synchronization problems.
|
||||||
|
+ This should also improve support for more types of SD cards.
|
||||||
|
+ A bug was fixed that caused emummc to not work on lower system versions due to missing SVC access.
|
||||||
|
+ **Please note**: The configuration entries used for emummc have been changed.
|
||||||
|
+ `emummc_` prefixes have been removed, since they are superfluous given the `emummc` category they are under.
|
||||||
|
+ As an example, `emummc!emummc_enabled` is now `emummc!enabled`.
|
||||||
|
+ INI configurations made by @CTCaer's [tool](https://github.com/ctcaer/hekate/releases/latest) (which is the recommended way to manage emummc) should automatically work as expected/be corrected.
|
||||||
|
+ **If you do not wish to use the above, you will need to manually correct your configuration file**.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
|
+ Stratosphere is currently in the process of being re-written/refactored.
|
||||||
|
+ Stratosphere was my (SciresM's) first C++ project, ever -- the code written for it a year ago when I was learning C++ is/was of much lower quality than code written more recently.
|
||||||
|
+ Code is thus being re-rwitten for clarity/stlye/to de-duplicate functionality, with much being moved into libstratosphere.
|
||||||
|
+ Stratosphere will, after the rewrite, globally use the `sts::` namespace -- this should greatly enhancing libstratosphere's ability to provide functionality for system modules.
|
||||||
|
+ The rewritten modules consistently have lower memory footprints, and should be easier to maintain going forwards.
|
||||||
|
+ The `sm`, `boot`, `spl`, `ro`, and `loader` modules have been tackled so far.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
## 0.9.1
|
## 0.9.1
|
||||||
+ Support was added for 8.1.0.
|
+ Support was added for 8.1.0.
|
||||||
+ Please note, emummc is still considered **beta/experimental** -- this is not the inevitable bugfix update for it, although some number of bugs have been fixed. :)
|
+ Please note, emummc is still considered **beta/experimental** -- this is not the inevitable bugfix update for it, although some number of bugs have been fixed. :)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
[subrepo]
|
[subrepo]
|
||||||
remote = https://github.com/m4xw/emuMMC
|
remote = https://github.com/m4xw/emuMMC
|
||||||
branch = develop
|
branch = develop
|
||||||
commit = e7799388e8d3de17fd178ffe310be2e81ef46d6f
|
commit = 5f51fa3b81d2b14b348f6e8579454007019fc7a6
|
||||||
parent = f2086fe05492cb523b60fa10e4425c4ea59521b3
|
parent = e871a754a87631c3036ca985ff1c223e00ef4dda
|
||||||
method = rebase
|
method = rebase
|
||||||
cmdver = 0.4.0
|
cmdver = 0.4.0
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
|
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
|
||||||
|
|
||||||
### Supported Horizon Versions
|
### Supported Horizon Versions
|
||||||
**1.0.0 - 8.0.1**
|
**1.0.0 - 8.1.0**
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Arbitrary SDMMC backend selection
|
* Arbitrary SDMMC backend selection
|
||||||
|
|||||||
@@ -116,6 +116,7 @@
|
|||||||
"svcReplyAndReceive": "0x43",
|
"svcReplyAndReceive": "0x43",
|
||||||
"svcReplyAndReceiveWithUserBuffer": "0x44",
|
"svcReplyAndReceiveWithUserBuffer": "0x44",
|
||||||
"svcCreateEvent": "0x45",
|
"svcCreateEvent": "0x45",
|
||||||
|
"svcReadWriteRegister": "0x4E",
|
||||||
"svcCreateInterruptEvent": "0x53",
|
"svcCreateInterruptEvent": "0x53",
|
||||||
"svcQueryIoMapping": "0x55",
|
"svcQueryIoMapping": "0x55",
|
||||||
"svcCreateDeviceAddressSpace": "0x56",
|
"svcCreateDeviceAddressSpace": "0x56",
|
||||||
|
|||||||
@@ -47,23 +47,23 @@
|
|||||||
|
|
||||||
#define DEFINE_OFFSET_STRUCT(vers) \
|
#define DEFINE_OFFSET_STRUCT(vers) \
|
||||||
static const fs_offsets_t GET_OFFSET_STRUCT_NAME(vers) = { \
|
static const fs_offsets_t GET_OFFSET_STRUCT_NAME(vers) = { \
|
||||||
.sdmmc_accessor_gc = FS_OFFSET##vers##_SDMMC_ACCESSOR_GC, \
|
.sdmmc_accessor_gc = FS_OFFSET##vers##_SDMMC_ACCESSOR_GC, \
|
||||||
.sdmmc_accessor_sd = FS_OFFSET##vers##_SDMMC_ACCESSOR_SD, \
|
.sdmmc_accessor_sd = FS_OFFSET##vers##_SDMMC_ACCESSOR_SD, \
|
||||||
.sdmmc_accessor_nand = FS_OFFSET##vers##_SDMMC_ACCESSOR_NAND, \
|
.sdmmc_accessor_nand = FS_OFFSET##vers##_SDMMC_ACCESSOR_NAND, \
|
||||||
.sdmmc_wrapper_read = FS_OFFSET##vers##_SDMMC_WRAPPER_READ, \
|
.sdmmc_wrapper_read = FS_OFFSET##vers##_SDMMC_WRAPPER_READ, \
|
||||||
.sdmmc_wrapper_write = FS_OFFSET##vers##_SDMMC_WRAPPER_WRITE, \
|
.sdmmc_wrapper_write = FS_OFFSET##vers##_SDMMC_WRAPPER_WRITE, \
|
||||||
.clkrst_set_min_v_clock_rate = FS_OFFSET##vers##_CLKRST_SET_MIN_V_CLK_RATE, \
|
.clkrst_set_min_v_clock_rate = FS_OFFSET##vers##_CLKRST_SET_MIN_V_CLK_RATE, \
|
||||||
.rtld = FS_OFFSET##vers##_RTLD, \
|
.rtld = FS_OFFSET##vers##_RTLD, \
|
||||||
.rtld_destination = FS_OFFSET##vers##_RTLD_DESTINATION, \
|
.rtld_destination = FS_OFFSET##vers##_RTLD_DESTINATION, \
|
||||||
.lock_mutex = FS_OFFSET##vers##_LOCK_MUTEX, \
|
.lock_mutex = FS_OFFSET##vers##_LOCK_MUTEX, \
|
||||||
.unlock_mutex = FS_OFFSET##vers##_UNLOCK_MUTEX, \
|
.unlock_mutex = FS_OFFSET##vers##_UNLOCK_MUTEX, \
|
||||||
.sd_mutex = FS_OFFSET##vers##_SD_MUTEX, \
|
.sd_mutex = FS_OFFSET##vers##_SD_MUTEX, \
|
||||||
.nand_mutex = FS_OFFSET##vers##_NAND_MUTEX, \
|
.nand_mutex = FS_OFFSET##vers##_NAND_MUTEX, \
|
||||||
.active_partition = FS_OFFSET##vers##_ACTIVE_PARTITION, \
|
.active_partition = FS_OFFSET##vers##_ACTIVE_PARTITION, \
|
||||||
.sdmmc_das_handle = FS_OFFSET##vers##_SDMMC_DAS_HANDLE, \
|
.sdmmc_das_handle = FS_OFFSET##vers##_SDMMC_DAS_HANDLE, \
|
||||||
.shutdown_sd = FS_OFFSET##vers##_SHUTDOWN_SD, \
|
.sdmmc_accessor_controller_close = FS_OFFSET##vers##_SDMMC_WRAPPER_CONTROLLER_CLOSE, \
|
||||||
.sd_das_init = FS_OFFSET##vers##_SD_DAS_INIT, \
|
.sd_das_init = FS_OFFSET##vers##_SD_DAS_INIT, \
|
||||||
.nintendo_paths = FS_OFFSET##vers##_NINTENDO_PATHS, \
|
.nintendo_paths = FS_OFFSET##vers##_NINTENDO_PATHS, \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actually define offset structs
|
// Actually define offset structs
|
||||||
|
|||||||
@@ -41,13 +41,13 @@ typedef struct {
|
|||||||
// Misc funcs
|
// Misc funcs
|
||||||
uintptr_t lock_mutex;
|
uintptr_t lock_mutex;
|
||||||
uintptr_t unlock_mutex;
|
uintptr_t unlock_mutex;
|
||||||
|
uintptr_t sdmmc_accessor_controller_close;
|
||||||
// Misc data
|
// Misc data
|
||||||
uintptr_t sd_mutex;
|
uintptr_t sd_mutex;
|
||||||
uintptr_t nand_mutex;
|
uintptr_t nand_mutex;
|
||||||
uintptr_t active_partition;
|
uintptr_t active_partition;
|
||||||
uintptr_t sdmmc_das_handle;
|
uintptr_t sdmmc_das_handle;
|
||||||
// NOPs
|
// NOPs
|
||||||
uintptr_t shutdown_sd;
|
|
||||||
uintptr_t sd_das_init;
|
uintptr_t sd_das_init;
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
fs_offsets_nintendo_path_t nintendo_paths[];
|
fs_offsets_nintendo_path_t nintendo_paths[];
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ typedef struct sdmmc_accessor_vt
|
|||||||
void *map_device_addr_space;
|
void *map_device_addr_space;
|
||||||
void *unmap_device_addr_space;
|
void *unmap_device_addr_space;
|
||||||
void *controller_open;
|
void *controller_open;
|
||||||
void *controller_close;
|
uint64_t (*sdmmc_accessor_controller_close)(void *);
|
||||||
uint64_t (*read_write)(void *, uint64_t, uint64_t, void *, uint64_t, uint64_t);
|
uint64_t (*read_write)(void *, uint64_t, uint64_t, void *, uint64_t, uint64_t);
|
||||||
// More not included because we don't use it.
|
// More not included because we don't use it.
|
||||||
} sdmmc_accessor_vt_t;
|
} sdmmc_accessor_vt_t;
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_100_LOCK_MUTEX 0x2884
|
#define FS_OFFSET_100_LOCK_MUTEX 0x2884
|
||||||
#define FS_OFFSET_100_UNLOCK_MUTEX 0x28F0
|
#define FS_OFFSET_100_UNLOCK_MUTEX 0x28F0
|
||||||
|
|
||||||
|
#define FS_OFFSET_100_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x6A8AC
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_100_SD_MUTEX 0xE36058
|
#define FS_OFFSET_100_SD_MUTEX 0xE36058
|
||||||
#define FS_OFFSET_100_NAND_MUTEX 0xE30610
|
#define FS_OFFSET_100_NAND_MUTEX 0xE30610
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_100_SDMMC_DAS_HANDLE 0xE2F730
|
#define FS_OFFSET_100_SDMMC_DAS_HANDLE 0xE2F730
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_100_SHUTDOWN_SD 0x22548
|
|
||||||
#define FS_OFFSET_100_SD_DAS_INIT 0x0
|
#define FS_OFFSET_100_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_200_LOCK_MUTEX 0x3264
|
#define FS_OFFSET_200_LOCK_MUTEX 0x3264
|
||||||
#define FS_OFFSET_200_UNLOCK_MUTEX 0x32D0
|
#define FS_OFFSET_200_UNLOCK_MUTEX 0x32D0
|
||||||
|
|
||||||
|
#define FS_OFFSET_200_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x733F4
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_200_SD_MUTEX 0xE42268
|
#define FS_OFFSET_200_SD_MUTEX 0xE42268
|
||||||
#define FS_OFFSET_200_NAND_MUTEX 0xE3CED0
|
#define FS_OFFSET_200_NAND_MUTEX 0xE3CED0
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_200_SDMMC_DAS_HANDLE 0xE3BDD0
|
#define FS_OFFSET_200_SDMMC_DAS_HANDLE 0xE3BDD0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_200_SHUTDOWN_SD 0x20C48
|
|
||||||
#define FS_OFFSET_200_SD_DAS_INIT 0x0
|
#define FS_OFFSET_200_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_200_EXFAT_LOCK_MUTEX 0x3264
|
#define FS_OFFSET_200_EXFAT_LOCK_MUTEX 0x3264
|
||||||
#define FS_OFFSET_200_EXFAT_UNLOCK_MUTEX 0x32D0
|
#define FS_OFFSET_200_EXFAT_UNLOCK_MUTEX 0x32D0
|
||||||
|
|
||||||
|
#define FS_OFFSET_200_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x733F4
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_200_EXFAT_SD_MUTEX 0xF22268
|
#define FS_OFFSET_200_EXFAT_SD_MUTEX 0xF22268
|
||||||
#define FS_OFFSET_200_EXFAT_NAND_MUTEX 0xF1CED0
|
#define FS_OFFSET_200_EXFAT_NAND_MUTEX 0xF1CED0
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_200_EXFAT_SDMMC_DAS_HANDLE 0xF1BDD0
|
#define FS_OFFSET_200_EXFAT_SDMMC_DAS_HANDLE 0xF1BDD0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_200_EXFAT_SHUTDOWN_SD 0x20C48
|
|
||||||
#define FS_OFFSET_200_EXFAT_SD_DAS_INIT 0x0
|
#define FS_OFFSET_200_EXFAT_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_210_LOCK_MUTEX 0x3264
|
#define FS_OFFSET_210_LOCK_MUTEX 0x3264
|
||||||
#define FS_OFFSET_210_UNLOCK_MUTEX 0x32D0
|
#define FS_OFFSET_210_UNLOCK_MUTEX 0x32D0
|
||||||
|
|
||||||
|
#define FS_OFFSET_210_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x737D4
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_210_SD_MUTEX 0xE43268
|
#define FS_OFFSET_210_SD_MUTEX 0xE43268
|
||||||
#define FS_OFFSET_210_NAND_MUTEX 0xE3DED0
|
#define FS_OFFSET_210_NAND_MUTEX 0xE3DED0
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_210_SDMMC_DAS_HANDLE 0xE3CDD0
|
#define FS_OFFSET_210_SDMMC_DAS_HANDLE 0xE3CDD0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_210_SHUTDOWN_SD 0x20E60
|
|
||||||
#define FS_OFFSET_210_SD_DAS_INIT 0x0
|
#define FS_OFFSET_210_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_210_EXFAT_LOCK_MUTEX 0x3264
|
#define FS_OFFSET_210_EXFAT_LOCK_MUTEX 0x3264
|
||||||
#define FS_OFFSET_210_EXFAT_UNLOCK_MUTEX 0x32D0
|
#define FS_OFFSET_210_EXFAT_UNLOCK_MUTEX 0x32D0
|
||||||
|
|
||||||
|
#define FS_OFFSET_210_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x737D4
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_210_EXFAT_SD_MUTEX 0xF22268
|
#define FS_OFFSET_210_EXFAT_SD_MUTEX 0xF22268
|
||||||
#define FS_OFFSET_210_EXFAT_NAND_MUTEX 0xF1CED0
|
#define FS_OFFSET_210_EXFAT_NAND_MUTEX 0xF1CED0
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_210_EXFAT_SDMMC_DAS_HANDLE 0xF1BDD0
|
#define FS_OFFSET_210_EXFAT_SDMMC_DAS_HANDLE 0xF1BDD0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_210_EXFAT_SHUTDOWN_SD 0x20E60
|
|
||||||
#define FS_OFFSET_210_EXFAT_SD_DAS_INIT 0x0
|
#define FS_OFFSET_210_EXFAT_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_300_LOCK_MUTEX 0x35CC
|
#define FS_OFFSET_300_LOCK_MUTEX 0x35CC
|
||||||
#define FS_OFFSET_300_UNLOCK_MUTEX 0x3638
|
#define FS_OFFSET_300_UNLOCK_MUTEX 0x3638
|
||||||
|
|
||||||
|
#define FS_OFFSET_300_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x8A270
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_300_SD_MUTEX 0xE69268
|
#define FS_OFFSET_300_SD_MUTEX 0xE69268
|
||||||
#define FS_OFFSET_300_NAND_MUTEX 0xE646F0
|
#define FS_OFFSET_300_NAND_MUTEX 0xE646F0
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_300_SDMMC_DAS_HANDLE 0xE635A0
|
#define FS_OFFSET_300_SDMMC_DAS_HANDLE 0xE635A0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_300_SHUTDOWN_SD 0x258D8
|
|
||||||
#define FS_OFFSET_300_SD_DAS_INIT 0x0
|
#define FS_OFFSET_300_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_300_EXFAT_LOCK_MUTEX 0x35CC
|
#define FS_OFFSET_300_EXFAT_LOCK_MUTEX 0x35CC
|
||||||
#define FS_OFFSET_300_EXFAT_UNLOCK_MUTEX 0x3638
|
#define FS_OFFSET_300_EXFAT_UNLOCK_MUTEX 0x3638
|
||||||
|
|
||||||
|
#define FS_OFFSET_300_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x8A270
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_300_EXFAT_SD_MUTEX 0xF4C268
|
#define FS_OFFSET_300_EXFAT_SD_MUTEX 0xF4C268
|
||||||
#define FS_OFFSET_300_EXFAT_NAND_MUTEX 0xF476F0
|
#define FS_OFFSET_300_EXFAT_NAND_MUTEX 0xF476F0
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_300_EXFAT_SDMMC_DAS_HANDLE 0xF465A0
|
#define FS_OFFSET_300_EXFAT_SDMMC_DAS_HANDLE 0xF465A0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_300_EXFAT_SHUTDOWN_SD 0x258D8
|
|
||||||
#define FS_OFFSET_300_EXFAT_SD_DAS_INIT 0x0
|
#define FS_OFFSET_300_EXFAT_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_301_LOCK_MUTEX 0x3638
|
#define FS_OFFSET_301_LOCK_MUTEX 0x3638
|
||||||
#define FS_OFFSET_301_UNLOCK_MUTEX 0x36A4
|
#define FS_OFFSET_301_UNLOCK_MUTEX 0x36A4
|
||||||
|
|
||||||
|
#define FS_OFFSET_301_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x8A32C
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_301_SD_MUTEX 0xE69268
|
#define FS_OFFSET_301_SD_MUTEX 0xE69268
|
||||||
#define FS_OFFSET_301_NAND_MUTEX 0xE646F0
|
#define FS_OFFSET_301_NAND_MUTEX 0xE646F0
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_301_SDMMC_DAS_HANDLE 0xE635A0
|
#define FS_OFFSET_301_SDMMC_DAS_HANDLE 0xE635A0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_301_SHUTDOWN_SD 0x25944
|
|
||||||
#define FS_OFFSET_301_SD_DAS_INIT 0x0
|
#define FS_OFFSET_301_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_301_EXFAT_LOCK_MUTEX 0x3638
|
#define FS_OFFSET_301_EXFAT_LOCK_MUTEX 0x3638
|
||||||
#define FS_OFFSET_301_EXFAT_UNLOCK_MUTEX 0x36A4
|
#define FS_OFFSET_301_EXFAT_UNLOCK_MUTEX 0x36A4
|
||||||
|
|
||||||
|
#define FS_OFFSET_301_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x8A32C
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_301_EXFAT_SD_MUTEX 0xF4C268
|
#define FS_OFFSET_301_EXFAT_SD_MUTEX 0xF4C268
|
||||||
#define FS_OFFSET_301_EXFAT_NAND_MUTEX 0xF476F0
|
#define FS_OFFSET_301_EXFAT_NAND_MUTEX 0xF476F0
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_301_EXFAT_SDMMC_DAS_HANDLE 0xF465A0
|
#define FS_OFFSET_301_EXFAT_SDMMC_DAS_HANDLE 0xF465A0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_301_EXFAT_SHUTDOWN_SD 0x25944
|
|
||||||
#define FS_OFFSET_301_EXFAT_SD_DAS_INIT 0x0
|
#define FS_OFFSET_301_EXFAT_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_400_LOCK_MUTEX 0x39A0
|
#define FS_OFFSET_400_LOCK_MUTEX 0x39A0
|
||||||
#define FS_OFFSET_400_UNLOCK_MUTEX 0x3A0C
|
#define FS_OFFSET_400_UNLOCK_MUTEX 0x3A0C
|
||||||
|
|
||||||
|
#define FS_OFFSET_400_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x9DB48
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_400_SD_MUTEX 0xE80268
|
#define FS_OFFSET_400_SD_MUTEX 0xE80268
|
||||||
#define FS_OFFSET_400_NAND_MUTEX 0xE7BC60
|
#define FS_OFFSET_400_NAND_MUTEX 0xE7BC60
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_400_SDMMC_DAS_HANDLE 0xE7ABF0
|
#define FS_OFFSET_400_SDMMC_DAS_HANDLE 0xE7ABF0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_400_SHUTDOWN_SD 0x32D70
|
|
||||||
#define FS_OFFSET_400_SD_DAS_INIT 0x0
|
#define FS_OFFSET_400_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_400_EXFAT_LOCK_MUTEX 0x39A0
|
#define FS_OFFSET_400_EXFAT_LOCK_MUTEX 0x39A0
|
||||||
#define FS_OFFSET_400_EXFAT_UNLOCK_MUTEX 0x3A0C
|
#define FS_OFFSET_400_EXFAT_UNLOCK_MUTEX 0x3A0C
|
||||||
|
|
||||||
|
#define FS_OFFSET_400_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x9DB48
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_400_EXFAT_SD_MUTEX 0xF63268
|
#define FS_OFFSET_400_EXFAT_SD_MUTEX 0xF63268
|
||||||
#define FS_OFFSET_400_EXFAT_NAND_MUTEX 0xF5EC60
|
#define FS_OFFSET_400_EXFAT_NAND_MUTEX 0xF5EC60
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_400_EXFAT_SDMMC_DAS_HANDLE 0xF5DBF0
|
#define FS_OFFSET_400_EXFAT_SDMMC_DAS_HANDLE 0xF5DBF0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_400_EXFAT_SHUTDOWN_SD 0x32D70
|
|
||||||
#define FS_OFFSET_400_EXFAT_SD_DAS_INIT 0x0
|
#define FS_OFFSET_400_EXFAT_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_410_LOCK_MUTEX 0x39A0
|
#define FS_OFFSET_410_LOCK_MUTEX 0x39A0
|
||||||
#define FS_OFFSET_410_UNLOCK_MUTEX 0x3A0C
|
#define FS_OFFSET_410_UNLOCK_MUTEX 0x3A0C
|
||||||
|
|
||||||
|
#define FS_OFFSET_410_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x9DBAC
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_410_SD_MUTEX 0xE80268
|
#define FS_OFFSET_410_SD_MUTEX 0xE80268
|
||||||
#define FS_OFFSET_410_NAND_MUTEX 0xE7BC60
|
#define FS_OFFSET_410_NAND_MUTEX 0xE7BC60
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_410_SDMMC_DAS_HANDLE 0xE7ABF0
|
#define FS_OFFSET_410_SDMMC_DAS_HANDLE 0xE7ABF0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_410_SHUTDOWN_SD 0x32D70
|
|
||||||
#define FS_OFFSET_410_SD_DAS_INIT 0x0
|
#define FS_OFFSET_410_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_410_EXFAT_LOCK_MUTEX 0x39A0
|
#define FS_OFFSET_410_EXFAT_LOCK_MUTEX 0x39A0
|
||||||
#define FS_OFFSET_410_EXFAT_UNLOCK_MUTEX 0x3A0C
|
#define FS_OFFSET_410_EXFAT_UNLOCK_MUTEX 0x3A0C
|
||||||
|
|
||||||
|
#define FS_OFFSET_410_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x9DBAC
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_410_EXFAT_SD_MUTEX 0xF63268
|
#define FS_OFFSET_410_EXFAT_SD_MUTEX 0xF63268
|
||||||
#define FS_OFFSET_410_EXFAT_NAND_MUTEX 0xF5EC60
|
#define FS_OFFSET_410_EXFAT_NAND_MUTEX 0xF5EC60
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_410_EXFAT_SDMMC_DAS_HANDLE 0xF5DBF0
|
#define FS_OFFSET_410_EXFAT_SDMMC_DAS_HANDLE 0xF5DBF0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_410_EXFAT_SHUTDOWN_SD 0x32D70
|
|
||||||
#define FS_OFFSET_410_EXFAT_SD_DAS_INIT 0x0
|
#define FS_OFFSET_410_EXFAT_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_500_LOCK_MUTEX 0x4080
|
#define FS_OFFSET_500_LOCK_MUTEX 0x4080
|
||||||
#define FS_OFFSET_500_UNLOCK_MUTEX 0x40D0
|
#define FS_OFFSET_500_UNLOCK_MUTEX 0x40D0
|
||||||
|
|
||||||
|
#define FS_OFFSET_500_SDMMC_WRAPPER_CONTROLLER_CLOSE 0xC9380
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_500_SD_MUTEX 0xEC3268
|
#define FS_OFFSET_500_SD_MUTEX 0xEC3268
|
||||||
#define FS_OFFSET_500_NAND_MUTEX 0xEBDE58
|
#define FS_OFFSET_500_NAND_MUTEX 0xEBDE58
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_500_SDMMC_DAS_HANDLE 0xEBCE30
|
#define FS_OFFSET_500_SDMMC_DAS_HANDLE 0xEBCE30
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_500_SHUTDOWN_SD 0x443E8
|
|
||||||
#define FS_OFFSET_500_SD_DAS_INIT 0x0
|
#define FS_OFFSET_500_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_500_EXFAT_LOCK_MUTEX 0x4080
|
#define FS_OFFSET_500_EXFAT_LOCK_MUTEX 0x4080
|
||||||
#define FS_OFFSET_500_EXFAT_UNLOCK_MUTEX 0x40D0
|
#define FS_OFFSET_500_EXFAT_UNLOCK_MUTEX 0x40D0
|
||||||
|
|
||||||
|
#define FS_OFFSET_500_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0xC9380
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_500_EXFAT_SD_MUTEX 0xFA8268
|
#define FS_OFFSET_500_EXFAT_SD_MUTEX 0xFA8268
|
||||||
#define FS_OFFSET_500_EXFAT_NAND_MUTEX 0xFA2E58
|
#define FS_OFFSET_500_EXFAT_NAND_MUTEX 0xFA2E58
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_500_EXFAT_SDMMC_DAS_HANDLE 0xFA1E30
|
#define FS_OFFSET_500_EXFAT_SDMMC_DAS_HANDLE 0xFA1E30
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_500_EXFAT_SHUTDOWN_SD 0x443E8
|
|
||||||
#define FS_OFFSET_500_EXFAT_SD_DAS_INIT 0x0
|
#define FS_OFFSET_500_EXFAT_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_510_LOCK_MUTEX 0x4080
|
#define FS_OFFSET_510_LOCK_MUTEX 0x4080
|
||||||
#define FS_OFFSET_510_UNLOCK_MUTEX 0x40D0
|
#define FS_OFFSET_510_UNLOCK_MUTEX 0x40D0
|
||||||
|
|
||||||
|
#define FS_OFFSET_510_SDMMC_WRAPPER_CONTROLLER_CLOSE 0xC9750
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_510_SD_MUTEX 0xEC4268
|
#define FS_OFFSET_510_SD_MUTEX 0xEC4268
|
||||||
#define FS_OFFSET_510_NAND_MUTEX 0xEBEE58
|
#define FS_OFFSET_510_NAND_MUTEX 0xEBEE58
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_510_SDMMC_DAS_HANDLE 0xEBDE30
|
#define FS_OFFSET_510_SDMMC_DAS_HANDLE 0xEBDE30
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_510_SHUTDOWN_SD 0x44578
|
|
||||||
#define FS_OFFSET_510_SD_DAS_INIT 0x0
|
#define FS_OFFSET_510_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_510_EXFAT_LOCK_MUTEX 0x4080
|
#define FS_OFFSET_510_EXFAT_LOCK_MUTEX 0x4080
|
||||||
#define FS_OFFSET_510_EXFAT_UNLOCK_MUTEX 0x40D0
|
#define FS_OFFSET_510_EXFAT_UNLOCK_MUTEX 0x40D0
|
||||||
|
|
||||||
|
#define FS_OFFSET_510_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0xC9750
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_510_EXFAT_SD_MUTEX 0xFA9268
|
#define FS_OFFSET_510_EXFAT_SD_MUTEX 0xFA9268
|
||||||
#define FS_OFFSET_510_EXFAT_NAND_MUTEX 0xFA3E58
|
#define FS_OFFSET_510_EXFAT_NAND_MUTEX 0xFA3E58
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_510_EXFAT_SDMMC_DAS_HANDLE 0xFA2E30
|
#define FS_OFFSET_510_EXFAT_SDMMC_DAS_HANDLE 0xFA2E30
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_510_EXFAT_SHUTDOWN_SD 0x44578
|
|
||||||
#define FS_OFFSET_510_EXFAT_SD_DAS_INIT 0x0
|
#define FS_OFFSET_510_EXFAT_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_600_LOCK_MUTEX 0x1412C0
|
#define FS_OFFSET_600_LOCK_MUTEX 0x1412C0
|
||||||
#define FS_OFFSET_600_UNLOCK_MUTEX 0x141310
|
#define FS_OFFSET_600_UNLOCK_MUTEX 0x141310
|
||||||
|
|
||||||
|
#define FS_OFFSET_600_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x148500
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_600_SD_MUTEX 0xF06268
|
#define FS_OFFSET_600_SD_MUTEX 0xF06268
|
||||||
#define FS_OFFSET_600_NAND_MUTEX 0xF01BA0
|
#define FS_OFFSET_600_NAND_MUTEX 0xF01BA0
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_600_SDMMC_DAS_HANDLE 0xE01670
|
#define FS_OFFSET_600_SDMMC_DAS_HANDLE 0xE01670
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_600_SHUTDOWN_SD 0xB2F28
|
|
||||||
#define FS_OFFSET_600_SD_DAS_INIT 0x0
|
#define FS_OFFSET_600_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_600_EXFAT_LOCK_MUTEX 0x14C9C0
|
#define FS_OFFSET_600_EXFAT_LOCK_MUTEX 0x14C9C0
|
||||||
#define FS_OFFSET_600_EXFAT_UNLOCK_MUTEX 0x14CA10
|
#define FS_OFFSET_600_EXFAT_UNLOCK_MUTEX 0x14CA10
|
||||||
|
|
||||||
|
#define FS_OFFSET_600_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x153C00
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_600_EXFAT_SD_MUTEX 0xFEB268
|
#define FS_OFFSET_600_EXFAT_SD_MUTEX 0xFEB268
|
||||||
#define FS_OFFSET_600_EXFAT_NAND_MUTEX 0xFE6BA0
|
#define FS_OFFSET_600_EXFAT_NAND_MUTEX 0xFE6BA0
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_600_EXFAT_SDMMC_DAS_HANDLE 0xEE6670
|
#define FS_OFFSET_600_EXFAT_SDMMC_DAS_HANDLE 0xEE6670
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_600_EXFAT_SHUTDOWN_SD 0xBE628
|
|
||||||
#define FS_OFFSET_600_EXFAT_SD_DAS_INIT 0x0
|
#define FS_OFFSET_600_EXFAT_SD_DAS_INIT 0x0
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_700_LOCK_MUTEX 0x148A90
|
#define FS_OFFSET_700_LOCK_MUTEX 0x148A90
|
||||||
#define FS_OFFSET_700_UNLOCK_MUTEX 0x148AE0
|
#define FS_OFFSET_700_UNLOCK_MUTEX 0x148AE0
|
||||||
|
|
||||||
|
#define FS_OFFSET_700_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x14FD50
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_700_SD_MUTEX 0xF123E8
|
#define FS_OFFSET_700_SD_MUTEX 0xF123E8
|
||||||
#define FS_OFFSET_700_NAND_MUTEX 0xF0DBE8
|
#define FS_OFFSET_700_NAND_MUTEX 0xF0DBE8
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_700_SDMMC_DAS_HANDLE 0xE0E7A0
|
#define FS_OFFSET_700_SDMMC_DAS_HANDLE 0xE0E7A0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_700_SHUTDOWN_SD 0xB8FCC
|
|
||||||
#define FS_OFFSET_700_SD_DAS_INIT 0x85FE8
|
#define FS_OFFSET_700_SD_DAS_INIT 0x85FE8
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_700_EXFAT_LOCK_MUTEX 0x154040
|
#define FS_OFFSET_700_EXFAT_LOCK_MUTEX 0x154040
|
||||||
#define FS_OFFSET_700_EXFAT_UNLOCK_MUTEX 0x154090
|
#define FS_OFFSET_700_EXFAT_UNLOCK_MUTEX 0x154090
|
||||||
|
|
||||||
|
#define FS_OFFSET_700_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x15B300
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_700_EXFAT_SD_MUTEX 0xFF73E8
|
#define FS_OFFSET_700_EXFAT_SD_MUTEX 0xFF73E8
|
||||||
#define FS_OFFSET_700_EXFAT_NAND_MUTEX 0xFF2BE8
|
#define FS_OFFSET_700_EXFAT_NAND_MUTEX 0xFF2BE8
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_700_EXFAT_SDMMC_DAS_HANDLE 0xEF3A00
|
#define FS_OFFSET_700_EXFAT_SDMMC_DAS_HANDLE 0xEF3A00
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_700_EXFAT_SHUTDOWN_SD 0xC457C
|
|
||||||
#define FS_OFFSET_700_EXFAT_SD_DAS_INIT 0x91598
|
#define FS_OFFSET_700_EXFAT_SD_DAS_INIT 0x91598
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_800_LOCK_MUTEX 0x14B6D0
|
#define FS_OFFSET_800_LOCK_MUTEX 0x14B6D0
|
||||||
#define FS_OFFSET_800_UNLOCK_MUTEX 0x14B720
|
#define FS_OFFSET_800_UNLOCK_MUTEX 0x14B720
|
||||||
|
|
||||||
|
#define FS_OFFSET_800_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1529E0
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_800_SD_MUTEX 0xF1A3E8
|
#define FS_OFFSET_800_SD_MUTEX 0xF1A3E8
|
||||||
#define FS_OFFSET_800_NAND_MUTEX 0xF15BE8
|
#define FS_OFFSET_800_NAND_MUTEX 0xF15BE8
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_800_SDMMC_DAS_HANDLE 0xE167C0
|
#define FS_OFFSET_800_SDMMC_DAS_HANDLE 0xE167C0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_800_SHUTDOWN_SD 0xBAF6C
|
|
||||||
#define FS_OFFSET_800_SD_DAS_INIT 0x87D58
|
#define FS_OFFSET_800_SD_DAS_INIT 0x87D58
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_800_EXFAT_LOCK_MUTEX 0x156C80
|
#define FS_OFFSET_800_EXFAT_LOCK_MUTEX 0x156C80
|
||||||
#define FS_OFFSET_800_EXFAT_UNLOCK_MUTEX 0x156CD0
|
#define FS_OFFSET_800_EXFAT_UNLOCK_MUTEX 0x156CD0
|
||||||
|
|
||||||
|
#define FS_OFFSET_800_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x15DF90
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_800_EXFAT_SD_MUTEX 0xFFE3E8
|
#define FS_OFFSET_800_EXFAT_SD_MUTEX 0xFFE3E8
|
||||||
#define FS_OFFSET_800_EXFAT_NAND_MUTEX 0xFF9BE8
|
#define FS_OFFSET_800_EXFAT_NAND_MUTEX 0xFF9BE8
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_800_EXFAT_SDMMC_DAS_HANDLE 0xEFAA20
|
#define FS_OFFSET_800_EXFAT_SDMMC_DAS_HANDLE 0xEFAA20
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_800_EXFAT_SHUTDOWN_SD 0xC651C
|
|
||||||
#define FS_OFFSET_800_EXFAT_SD_DAS_INIT 0x93308
|
#define FS_OFFSET_800_EXFAT_SD_DAS_INIT 0x93308
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_810_LOCK_MUTEX 0x14B6D0
|
#define FS_OFFSET_810_LOCK_MUTEX 0x14B6D0
|
||||||
#define FS_OFFSET_810_UNLOCK_MUTEX 0x14B720
|
#define FS_OFFSET_810_UNLOCK_MUTEX 0x14B720
|
||||||
|
|
||||||
|
#define FS_OFFSET_810_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x1529E0
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_810_SD_MUTEX 0xF1A3E8
|
#define FS_OFFSET_810_SD_MUTEX 0xF1A3E8
|
||||||
#define FS_OFFSET_810_NAND_MUTEX 0xF15BE8
|
#define FS_OFFSET_810_NAND_MUTEX 0xF15BE8
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_810_SDMMC_DAS_HANDLE 0xE167C0
|
#define FS_OFFSET_810_SDMMC_DAS_HANDLE 0xE167C0
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_810_SHUTDOWN_SD 0xBAF6C
|
|
||||||
#define FS_OFFSET_810_SD_DAS_INIT 0x87D58
|
#define FS_OFFSET_810_SD_DAS_INIT 0x87D58
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#define FS_OFFSET_810_EXFAT_LOCK_MUTEX 0x156C80
|
#define FS_OFFSET_810_EXFAT_LOCK_MUTEX 0x156C80
|
||||||
#define FS_OFFSET_810_EXFAT_UNLOCK_MUTEX 0x156CD0
|
#define FS_OFFSET_810_EXFAT_UNLOCK_MUTEX 0x156CD0
|
||||||
|
|
||||||
|
#define FS_OFFSET_810_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x15DF90
|
||||||
|
|
||||||
// Misc Data
|
// Misc Data
|
||||||
#define FS_OFFSET_810_EXFAT_SD_MUTEX 0xFFE3E8
|
#define FS_OFFSET_810_EXFAT_SD_MUTEX 0xFFE3E8
|
||||||
#define FS_OFFSET_810_EXFAT_NAND_MUTEX 0xFF9BE8
|
#define FS_OFFSET_810_EXFAT_NAND_MUTEX 0xFF9BE8
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
#define FS_OFFSET_810_EXFAT_SDMMC_DAS_HANDLE 0xEFAA20
|
#define FS_OFFSET_810_EXFAT_SDMMC_DAS_HANDLE 0xEFAA20
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
#define FS_OFFSET_810_EXFAT_SHUTDOWN_SD 0xC651C
|
|
||||||
#define FS_OFFSET_810_EXFAT_SD_DAS_INIT 0x93308
|
#define FS_OFFSET_810_EXFAT_SD_DAS_INIT 0x93308
|
||||||
|
|
||||||
// Nintendo Paths
|
// Nintendo Paths
|
||||||
|
|||||||
@@ -24,11 +24,13 @@
|
|||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
#include "../utils/fatal.h"
|
#include "../utils/fatal.h"
|
||||||
|
#include "../emuMMC/emummc.h"
|
||||||
|
|
||||||
#define DPRINTF(...) //fprintf(stdout, __VA_ARGS__)
|
#define DPRINTF(...) //fprintf(stdout, __VA_ARGS__)
|
||||||
|
|
||||||
sdmmc_accessor_t *_current_accessor = NULL;
|
sdmmc_accessor_t *_current_accessor = NULL;
|
||||||
bool sdmmc_memcpy_buf = false;
|
bool sdmmc_memcpy_buf = false;
|
||||||
|
extern bool custom_driver;
|
||||||
|
|
||||||
static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)
|
static inline u32 unstuff_bits(u32 *resp, u32 start, u32 size)
|
||||||
{
|
{
|
||||||
@@ -52,25 +54,25 @@ intptr_t sdmmc_calculate_dma_addr(sdmmc_accessor_t *_this, void *buf, unsigned i
|
|||||||
char *_buf = (char *)buf;
|
char *_buf = (char *)buf;
|
||||||
char *actual_buf_start = _buf;
|
char *actual_buf_start = _buf;
|
||||||
char *actual_buf_end = &_buf[512 * num_sectors];
|
char *actual_buf_end = &_buf[512 * num_sectors];
|
||||||
char *dma_buffer_start = _this->parent->dmaBuffers[FS_SDMMC_EMMC].device_addr_buffer;
|
char *dma_buffer_start = _this->parent->dmaBuffers[0].device_addr_buffer;
|
||||||
|
|
||||||
if (dma_buffer_start <= _buf && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[FS_SDMMC_EMMC].device_addr_buffer_size])
|
if (dma_buffer_start <= _buf && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[0].device_addr_buffer_size])
|
||||||
{
|
{
|
||||||
dma_buf_idx = FS_SDMMC_EMMC;
|
dma_buf_idx = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dma_buffer_start = _this->parent->dmaBuffers[FS_SDMMC_SD].device_addr_buffer;
|
dma_buffer_start = _this->parent->dmaBuffers[1].device_addr_buffer;
|
||||||
if (dma_buffer_start <= actual_buf_start && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[FS_SDMMC_SD].device_addr_buffer_size])
|
if (dma_buffer_start <= actual_buf_start && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[1].device_addr_buffer_size])
|
||||||
{
|
{
|
||||||
dma_buf_idx = FS_SDMMC_SD;
|
dma_buf_idx = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dma_buffer_start = _this->parent->dmaBuffers[FS_SDMMC_GC].device_addr_buffer;
|
dma_buffer_start = _this->parent->dmaBuffers[2].device_addr_buffer;
|
||||||
if (dma_buffer_start <= actual_buf_start && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[FS_SDMMC_GC].device_addr_buffer_size])
|
if (dma_buffer_start <= actual_buf_start && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[2].device_addr_buffer_size])
|
||||||
{
|
{
|
||||||
dma_buf_idx = FS_SDMMC_GC;
|
dma_buf_idx = 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -86,30 +88,69 @@ intptr_t sdmmc_calculate_dma_addr(sdmmc_accessor_t *_this, void *buf, unsigned i
|
|||||||
return admaaddr;
|
return admaaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sdmmc_get_fitting_dma_index(sdmmc_accessor_t *_this, unsigned int num_sectors)
|
int sdmmc_calculate_dma_index(sdmmc_accessor_t *_this, void *buf, unsigned int num_sectors)
|
||||||
{
|
{
|
||||||
int dma_buf_idx = 0;
|
int dma_buf_idx = 0;
|
||||||
int blkSize = num_sectors * 512;
|
char *_buf = (char *)buf;
|
||||||
|
char *actual_buf_start = _buf;
|
||||||
|
char *actual_buf_end = &_buf[512 * num_sectors];
|
||||||
|
char *dma_buffer_start = _this->parent->dmaBuffers[0].device_addr_buffer;
|
||||||
|
|
||||||
if (_this->parent->dmaBuffers[FS_SDMMC_EMMC].device_addr_buffer_size >= blkSize)
|
if (dma_buffer_start <= _buf && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[0].device_addr_buffer_size])
|
||||||
{
|
{
|
||||||
dma_buf_idx = FS_SDMMC_EMMC;
|
dma_buf_idx = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_this->parent->dmaBuffers[FS_SDMMC_SD].device_addr_buffer_size >= blkSize)
|
dma_buffer_start = _this->parent->dmaBuffers[1].device_addr_buffer;
|
||||||
|
if (dma_buffer_start <= actual_buf_start && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[1].device_addr_buffer_size])
|
||||||
{
|
{
|
||||||
dma_buf_idx = FS_SDMMC_SD;
|
dma_buf_idx = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_this->parent->dmaBuffers[FS_SDMMC_GC].device_addr_buffer_size >= blkSize)
|
dma_buffer_start = _this->parent->dmaBuffers[2].device_addr_buffer;
|
||||||
|
if (dma_buffer_start <= actual_buf_start && actual_buf_end <= &dma_buffer_start[_this->parent->dmaBuffers[2].device_addr_buffer_size])
|
||||||
{
|
{
|
||||||
dma_buf_idx = FS_SDMMC_GC;
|
dma_buf_idx = 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If buffer is on a random heap
|
// If buffer is on a random heap
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sdmmc_memcpy_buf = false;
|
||||||
|
|
||||||
|
return dma_buf_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sdmmc_calculate_fitting_dma_index(sdmmc_accessor_t *_this, unsigned int num_sectors)
|
||||||
|
{
|
||||||
|
int dma_buf_idx = 0;
|
||||||
|
int blkSize = num_sectors * 512;
|
||||||
|
|
||||||
|
if (_this->parent->dmaBuffers[0].device_addr_buffer_size >= blkSize)
|
||||||
|
{
|
||||||
|
dma_buf_idx = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_this->parent->dmaBuffers[1].device_addr_buffer_size >= blkSize)
|
||||||
|
{
|
||||||
|
dma_buf_idx = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_this->parent->dmaBuffers[2].device_addr_buffer_size >= blkSize)
|
||||||
|
{
|
||||||
|
dma_buf_idx = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Can't find a fitting buffer
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -266,14 +307,112 @@ out:;
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern _sdmmc_accessor_sd sdmmc_accessor_sd;
|
||||||
|
extern _sdmmc_accessor_nand sdmmc_accessor_nand;
|
||||||
int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
int sdmmc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
||||||
{
|
{
|
||||||
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 0);
|
if (!custom_driver)
|
||||||
|
{
|
||||||
|
sdmmc_accessor_t *accessor_sd = sdmmc_accessor_sd();
|
||||||
|
sdmmc_accessor_t *accessor_nand = sdmmc_accessor_nand();
|
||||||
|
|
||||||
|
if (sdmmc_calculate_dma_addr(accessor_sd, buf, num_sectors))
|
||||||
|
{
|
||||||
|
return !accessor_sd->vtab->read_write(accessor_sd, sector, num_sectors, buf, num_sectors * 512, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (sdmmc_calculate_dma_addr(accessor_nand, buf, num_sectors))
|
||||||
|
{
|
||||||
|
// buf is on the nand dma buffer
|
||||||
|
int original_dma_idx = sdmmc_calculate_dma_index(accessor_nand, buf, num_sectors);
|
||||||
|
sdmmc_dma_buffer_t *original_dma_buffer = &accessor_nand->parent->dmaBuffers[original_dma_idx];
|
||||||
|
|
||||||
|
// Next entry
|
||||||
|
int dma_idx = sdmmc_calculate_fitting_dma_index(accessor_sd, num_sectors) + 1;
|
||||||
|
|
||||||
|
accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer = original_dma_buffer->device_addr_buffer;
|
||||||
|
accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_masked = original_dma_buffer->device_addr_buffer_masked;
|
||||||
|
accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_size = original_dma_buffer->device_addr_buffer_size;
|
||||||
|
|
||||||
|
u64 res = accessor_sd->vtab->read_write(accessor_sd, sector, num_sectors, buf, num_sectors * 512, 1);
|
||||||
|
|
||||||
|
accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer = 0;
|
||||||
|
accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_masked = 0;
|
||||||
|
accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_size = 0;
|
||||||
|
|
||||||
|
return !res;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// buf is on a heap
|
||||||
|
int dma_idx = sdmmc_calculate_fitting_dma_index(accessor_sd, num_sectors);
|
||||||
|
void *dma_buf = &accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer[0];
|
||||||
|
|
||||||
|
u64 res = accessor_sd->vtab->read_write(accessor_sd, sector, num_sectors, dma_buf, num_sectors * 512, 1);
|
||||||
|
memcpy(buf, dma_buf, num_sectors * 512);
|
||||||
|
|
||||||
|
return !res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
int sdmmc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
||||||
{
|
{
|
||||||
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 1);
|
if (!custom_driver)
|
||||||
|
{
|
||||||
|
sdmmc_accessor_t *accessor_sd = sdmmc_accessor_sd();
|
||||||
|
sdmmc_accessor_t *accessor_nand = sdmmc_accessor_nand();
|
||||||
|
|
||||||
|
if (sdmmc_calculate_dma_addr(accessor_sd, buf, num_sectors))
|
||||||
|
{
|
||||||
|
return !accessor_sd->vtab->read_write(accessor_sd, sector, num_sectors, buf, num_sectors * 512, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (sdmmc_calculate_dma_addr(accessor_nand, buf, num_sectors))
|
||||||
|
{
|
||||||
|
// buf is on the nand dma buffer
|
||||||
|
int original_dma_idx = sdmmc_calculate_dma_index(accessor_nand, buf, num_sectors);
|
||||||
|
sdmmc_dma_buffer_t *original_dma_buffer = &accessor_nand->parent->dmaBuffers[original_dma_idx];
|
||||||
|
|
||||||
|
// Next entry
|
||||||
|
int dma_idx = sdmmc_calculate_fitting_dma_index(accessor_sd, num_sectors) + 1;
|
||||||
|
|
||||||
|
accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer = original_dma_buffer->device_addr_buffer;
|
||||||
|
accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_masked = original_dma_buffer->device_addr_buffer_masked;
|
||||||
|
accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_size = original_dma_buffer->device_addr_buffer_size;
|
||||||
|
|
||||||
|
u64 res = accessor_sd->vtab->read_write(accessor_sd, sector, num_sectors, buf, num_sectors * 512, 0);
|
||||||
|
|
||||||
|
accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer = 0;
|
||||||
|
accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_masked = 0;
|
||||||
|
accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer_size = 0;
|
||||||
|
|
||||||
|
return !res;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// buf is on a heap
|
||||||
|
int dma_idx = sdmmc_calculate_fitting_dma_index(accessor_sd, num_sectors);
|
||||||
|
void *dma_buf = &accessor_sd->parent->dmaBuffers[dma_idx].device_addr_buffer[0];
|
||||||
|
|
||||||
|
memcpy(dma_buf, buf, num_sectors * 512);
|
||||||
|
u64 res = accessor_sd->vtab->read_write(accessor_sd, sector, num_sectors, dma_buf, num_sectors * 512, 0);
|
||||||
|
|
||||||
|
return !res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _sdmmc_storage_readwrite(storage, sector, num_sectors, buf, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -703,7 +842,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
|
|||||||
if (cond & SD_OCR_CCS)
|
if (cond & SD_OCR_CCS)
|
||||||
storage->has_sector_access = 1;
|
storage->has_sector_access = 1;
|
||||||
|
|
||||||
if (false && cond & SD_ROCR_S18A && supports_low_voltage)
|
if (cond & SD_ROCR_S18A && supports_low_voltage)
|
||||||
{
|
{
|
||||||
//The low voltage regulator configuration is valid for SDMMC1 only.
|
//The low voltage regulator configuration is valid for SDMMC1 only.
|
||||||
if (storage->sdmmc->id == SDMMC_1 &&
|
if (storage->sdmmc->id == SDMMC_1 &&
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ int sdmmc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
|
|||||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
|
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type);
|
||||||
int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
int sdmmc_storage_init_gc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
||||||
intptr_t sdmmc_calculate_dma_addr(sdmmc_accessor_t *_this, void *buf, unsigned int num_sectors);
|
intptr_t sdmmc_calculate_dma_addr(sdmmc_accessor_t *_this, void *buf, unsigned int num_sectors);
|
||||||
int sdmmc_get_fitting_dma_index(sdmmc_accessor_t *_this, unsigned int num_sectors);
|
int sdmmc_calculate_dma_index(sdmmc_accessor_t *_this, void *buf, unsigned int num_sectors);
|
||||||
|
int sdmmc_calculate_fitting_dma_index(sdmmc_accessor_t *_this, unsigned int num_sectors);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -641,23 +641,6 @@ static int _sdmmc_autocal_config_offset(sdmmc_t *sdmmc, u32 power)
|
|||||||
|
|
||||||
static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)
|
static void _sdmmc_autocal_execute(sdmmc_t *sdmmc, u32 power)
|
||||||
{
|
{
|
||||||
if(sdmmc->id == SDMMC_1)
|
|
||||||
{
|
|
||||||
static int last_power = SDMMC_POWER_3_3;
|
|
||||||
if(power == SDMMC_POWER_1_8 && last_power == SDMMC_POWER_3_3)
|
|
||||||
{
|
|
||||||
last_power = power = SDMMC_POWER_1_8;
|
|
||||||
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if(power == SDMMC_POWER_3_3 && last_power == SDMMC_POWER_1_8)
|
|
||||||
{
|
|
||||||
last_power = power = SDMMC_POWER_3_3;
|
|
||||||
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool should_enable_sd_clock = false;
|
bool should_enable_sd_clock = false;
|
||||||
if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)
|
if (sdmmc->regs->clkcon & TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE)
|
||||||
{
|
{
|
||||||
@@ -811,7 +794,7 @@ static int _sdmmc_config_dma(sdmmc_t *sdmmc, u32 *blkcnt_out, sdmmc_req_t *req)
|
|||||||
if (!admaaddr)
|
if (!admaaddr)
|
||||||
{
|
{
|
||||||
// buf is on a heap
|
// buf is on a heap
|
||||||
int dma_idx = sdmmc_get_fitting_dma_index(_current_accessor, blkcnt);
|
int dma_idx = sdmmc_calculate_fitting_dma_index(_current_accessor, blkcnt);
|
||||||
admaaddr = (u64)&_current_accessor->parent->dmaBuffers[dma_idx].device_addr_buffer_masked[0];
|
admaaddr = (u64)&_current_accessor->parent->dmaBuffers[dma_idx].device_addr_buffer_masked[0];
|
||||||
sdmmc->last_dma_idx = dma_idx;
|
sdmmc->last_dma_idx = dma_idx;
|
||||||
}
|
}
|
||||||
@@ -1011,10 +994,13 @@ static int _sdmmc_config_sdmmc1()
|
|||||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT1) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
||||||
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
PINMUX_AUX(PINMUX_AUX_SDMMC1_DAT0) = PINMUX_DRIVE_2X | PINMUX_INPUT_ENABLE | PINMUX_PARKED | PINMUX_PULL_UP;
|
||||||
|
|
||||||
|
//Make sure SDMMC1 controller is reset.
|
||||||
|
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_NO_IOPOWER, (1 << 12), (1 << 12));
|
||||||
|
usleep(1000);
|
||||||
|
|
||||||
//Make sure the SDMMC1 controller is powered.
|
//Make sure the SDMMC1 controller is powered.
|
||||||
//PMC(APBDEV_PMC_NO_IOPOWER) &= ~(1 << 12);
|
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_NO_IOPOWER, ~(1 << 12), (1 << 12));
|
||||||
//Assume 3.3V SD card voltage.
|
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, (1 << 12), (1 << 12));
|
||||||
//PMC(APBDEV_PMC_PWR_DET_VAL) |= (1 << 12);
|
|
||||||
|
|
||||||
//Set enable SD card power.
|
//Set enable SD card power.
|
||||||
PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | 1; //GPIO control, pull down.
|
PINMUX_AUX(PINMUX_AUX_DMIC3_CLK) = PINMUX_INPUT_ENABLE | PINMUX_PULL_DOWN | 1; //GPIO control, pull down.
|
||||||
@@ -1025,10 +1011,10 @@ static int _sdmmc_config_sdmmc1()
|
|||||||
usleep(1000);
|
usleep(1000);
|
||||||
|
|
||||||
//Enable SD card power.
|
//Enable SD card power.
|
||||||
//max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000);
|
max77620_regulator_set_voltage(REGULATOR_LDO2, 3300000);
|
||||||
//max77620_regulator_enable(REGULATOR_LDO2, 1);
|
max77620_regulator_enable(REGULATOR_LDO2, 1);
|
||||||
|
|
||||||
//usleep(1000);
|
usleep(1000);
|
||||||
|
|
||||||
//For good measure.
|
//For good measure.
|
||||||
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x10000000;
|
APB_MISC(APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL) = 0x10000000;
|
||||||
@@ -1071,7 +1057,7 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int n
|
|||||||
sdmmc->regs->veniotrimctl &= 0xFFFFFFFB;
|
sdmmc->regs->veniotrimctl &= 0xFFFFFFFB;
|
||||||
static const u32 trim_values[] = { 2, 8, 3, 8 };
|
static const u32 trim_values[] = { 2, 8, 3, 8 };
|
||||||
sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFF) | (trim_values[sdmmc->id] << 24);
|
sdmmc->regs->venclkctl = (sdmmc->regs->venclkctl & 0xE0FFFFFF) | (trim_values[sdmmc->id] << 24);
|
||||||
sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xF) | 7;
|
sdmmc->regs->sdmemcmppadctl = (sdmmc->regs->sdmemcmppadctl & 0xFFFFFFF0) | 7;
|
||||||
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
if (!_sdmmc_autocal_config_offset(sdmmc, power))
|
||||||
return 0;
|
return 0;
|
||||||
_sdmmc_autocal_execute(sdmmc, power);
|
_sdmmc_autocal_execute(sdmmc, power);
|
||||||
@@ -1103,8 +1089,9 @@ void sdmmc_end(sdmmc_t *sdmmc)
|
|||||||
if (sdmmc->id == SDMMC_1)
|
if (sdmmc->id == SDMMC_1)
|
||||||
{
|
{
|
||||||
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
|
gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE);
|
||||||
//max77620_regulator_enable(REGULATOR_LDO2, 0);
|
msleep(1); // To power cycle min 1ms without power is needed.
|
||||||
msleep(100); // To power cycle min 1ms without power is needed.
|
max77620_regulator_enable(REGULATOR_LDO2, 0);
|
||||||
|
msleep(100); // Some extra.
|
||||||
}
|
}
|
||||||
|
|
||||||
_sdmmc_get_clkcon(sdmmc);
|
_sdmmc_get_clkcon(sdmmc);
|
||||||
@@ -1158,7 +1145,7 @@ int sdmmc_enable_low_voltage(sdmmc_t *sdmmc)
|
|||||||
_sdmmc_get_clkcon(sdmmc);
|
_sdmmc_get_clkcon(sdmmc);
|
||||||
|
|
||||||
max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000);
|
max77620_regulator_set_voltage(REGULATOR_LDO2, 1800000);
|
||||||
PMC(APBDEV_PMC_PWR_DET_VAL) &= ~(1 << 12);
|
smcReadWriteRegister(PMC_BASE + APBDEV_PMC_PWR_DET_VAL, ~(1 << 12), (1 << 12));
|
||||||
|
|
||||||
_sdmmc_autocal_config_offset(sdmmc, SDMMC_POWER_1_8);
|
_sdmmc_autocal_config_offset(sdmmc, SDMMC_POWER_1_8);
|
||||||
_sdmmc_autocal_execute(sdmmc, SDMMC_POWER_1_8);
|
_sdmmc_autocal_execute(sdmmc, SDMMC_POWER_1_8);
|
||||||
|
|||||||
@@ -92,26 +92,9 @@ static void _sdmmc_ensure_initialized(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdmmc_finalize(void)
|
|
||||||
{
|
|
||||||
if (!sdmmc_storage_end(&sd_storage))
|
|
||||||
{
|
|
||||||
fatal_abort(Fatal_InitSD);
|
|
||||||
}
|
|
||||||
storageSDinitialized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _file_based_update_filename(char *outFilename, u32 sd_path_len, u32 part_idx)
|
static void _file_based_update_filename(char *outFilename, u32 sd_path_len, u32 part_idx)
|
||||||
{
|
{
|
||||||
if (part_idx < 10)
|
snprintf(outFilename + sd_path_len, 3, "%02d", part_idx);
|
||||||
{
|
|
||||||
outFilename[sd_path_len] = '0';
|
|
||||||
itoa(part_idx, &outFilename[sd_path_len + 1], 10);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
itoa(part_idx, &outFilename[sd_path_len], 10);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _file_based_emmc_finalize(void)
|
static void _file_based_emmc_finalize(void)
|
||||||
@@ -119,11 +102,13 @@ static void _file_based_emmc_finalize(void)
|
|||||||
if ((emuMMC_ctx.EMMC_Type == emuMMC_SD_File) && fat_mounted)
|
if ((emuMMC_ctx.EMMC_Type == emuMMC_SD_File) && fat_mounted)
|
||||||
{
|
{
|
||||||
// Close all open handles.
|
// Close all open handles.
|
||||||
f_close(f_emu.fp_boot0);
|
f_close(&f_emu.fp_boot0);
|
||||||
f_close(f_emu.fp_boot1);
|
f_close(&f_emu.fp_boot1);
|
||||||
|
|
||||||
for (int i = 0; i < f_emu.parts; i++)
|
for (int i = 0; i < f_emu.parts; i++)
|
||||||
f_close(f_emu.fp_gpp[i]);
|
{
|
||||||
|
f_close(&f_emu.fp_gpp[i]);
|
||||||
|
}
|
||||||
|
|
||||||
// Force unmount FAT volume.
|
// Force unmount FAT volume.
|
||||||
f_mount(NULL, "", 1);
|
f_mount(NULL, "", 1);
|
||||||
@@ -132,6 +117,18 @@ static void _file_based_emmc_finalize(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sdmmc_finalize(void)
|
||||||
|
{
|
||||||
|
_file_based_emmc_finalize();
|
||||||
|
|
||||||
|
if (!sdmmc_storage_end(&sd_storage))
|
||||||
|
{
|
||||||
|
fatal_abort(Fatal_InitSD);
|
||||||
|
}
|
||||||
|
|
||||||
|
storageSDinitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
static void _file_based_emmc_initialize(void)
|
static void _file_based_emmc_initialize(void)
|
||||||
{
|
{
|
||||||
char path[sizeof(emuMMC_ctx.storagePath) + 0x20];
|
char path[sizeof(emuMMC_ctx.storagePath) + 0x20];
|
||||||
@@ -143,36 +140,32 @@ static void _file_based_emmc_initialize(void)
|
|||||||
int path_len = strlen(path);
|
int path_len = strlen(path);
|
||||||
|
|
||||||
// Open BOOT0 physical partition.
|
// Open BOOT0 physical partition.
|
||||||
f_emu.fp_boot0 = (FIL *)malloc(sizeof(FIL));
|
|
||||||
memcpy(path + path_len, "BOOT0", 6);
|
memcpy(path + path_len, "BOOT0", 6);
|
||||||
if (f_open(f_emu.fp_boot0, path, FA_READ | FA_WRITE) != FR_OK)
|
if (f_open(&f_emu.fp_boot0, path, FA_READ | FA_WRITE) != FR_OK)
|
||||||
fatal_abort(Fatal_InitSD);
|
fatal_abort(Fatal_InitSD);
|
||||||
|
|
||||||
// Open BOOT1 physical partition.
|
// Open BOOT1 physical partition.
|
||||||
f_emu.fp_boot1 = (FIL *)malloc(sizeof(FIL));
|
|
||||||
memcpy(path + path_len, "BOOT1", 6);
|
memcpy(path + path_len, "BOOT1", 6);
|
||||||
if (f_open(f_emu.fp_boot1, path, FA_READ | FA_WRITE) != FR_OK)
|
if (f_open(&f_emu.fp_boot1, path, FA_READ | FA_WRITE) != FR_OK)
|
||||||
fatal_abort(Fatal_InitSD);
|
fatal_abort(Fatal_InitSD);
|
||||||
|
|
||||||
// Open handles for GPP physical partition files.
|
// Open handles for GPP physical partition files.
|
||||||
_file_based_update_filename(path, path_len, 00);
|
_file_based_update_filename(path, path_len, 00);
|
||||||
if (f_open(f_emu.fp_gpp[0], path, FA_READ | FA_WRITE) != FR_OK)
|
|
||||||
|
if (f_open(&f_emu.fp_gpp[0], path, FA_READ | FA_WRITE) != FR_OK)
|
||||||
fatal_abort(Fatal_InitSD);
|
fatal_abort(Fatal_InitSD);
|
||||||
|
|
||||||
f_emu.part_size = f_size(f_emu.fp_gpp[0]);
|
f_emu.part_size = f_size(&f_emu.fp_gpp[0]) >> 9;
|
||||||
|
|
||||||
// Iterate folder for split parts and stop if next doesn't exist.
|
// Iterate folder for split parts and stop if next doesn't exist.
|
||||||
// Supports up to 32 parts of any size.
|
// Supports up to 32 parts of any size.
|
||||||
// TODO: decide on max parts and define them. (hekate produces up to 30 parts on 1GB mode.)
|
// TODO: decide on max parts and define them. (hekate produces up to 30 parts on 1GB mode.)
|
||||||
for (f_emu.parts = 1; f_emu.parts < 32; f_emu.parts++)
|
for (f_emu.parts = 1; f_emu.parts < 32; f_emu.parts++)
|
||||||
{
|
{
|
||||||
f_emu.fp_gpp[f_emu.parts] = (FIL *)malloc(sizeof(FIL));
|
|
||||||
_file_based_update_filename(path, path_len, f_emu.parts);
|
_file_based_update_filename(path, path_len, f_emu.parts);
|
||||||
|
|
||||||
if (f_open(f_emu.fp_gpp[f_emu.parts], path, FA_READ | FA_WRITE) != FR_OK)
|
if (f_open(&f_emu.fp_gpp[f_emu.parts], path, FA_READ | FA_WRITE) != FR_OK)
|
||||||
{
|
{
|
||||||
free(f_emu.fp_gpp[f_emu.parts]);
|
|
||||||
|
|
||||||
// Check if single file.
|
// Check if single file.
|
||||||
if (f_emu.parts == 1)
|
if (f_emu.parts == 1)
|
||||||
f_emu.parts = 0;
|
f_emu.parts = 0;
|
||||||
@@ -257,14 +250,20 @@ sdmmc_accessor_t *sdmmc_accessor_get(int mmc_id)
|
|||||||
|
|
||||||
void mutex_lock_handler(int mmc_id)
|
void mutex_lock_handler(int mmc_id)
|
||||||
{
|
{
|
||||||
lock_mutex(sd_mutex);
|
if (custom_driver)
|
||||||
|
{
|
||||||
|
lock_mutex(sd_mutex);
|
||||||
|
}
|
||||||
lock_mutex(nand_mutex);
|
lock_mutex(nand_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mutex_unlock_handler(int mmc_id)
|
void mutex_unlock_handler(int mmc_id)
|
||||||
{
|
{
|
||||||
unlock_mutex(nand_mutex);
|
unlock_mutex(nand_mutex);
|
||||||
unlock_mutex(sd_mutex);
|
if (custom_driver)
|
||||||
|
{
|
||||||
|
unlock_mutex(sd_mutex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sdmmc_nand_get_active_partition_index()
|
int sdmmc_nand_get_active_partition_index()
|
||||||
@@ -303,19 +302,19 @@ static uint64_t emummc_read_write_inner(void *buf, unsigned int sector, unsigned
|
|||||||
case FS_EMMC_PARTITION_GPP:
|
case FS_EMMC_PARTITION_GPP:
|
||||||
if (f_emu.parts)
|
if (f_emu.parts)
|
||||||
{
|
{
|
||||||
fp_tmp = f_emu.fp_gpp[sector / f_emu.part_size];
|
fp_tmp = &f_emu.fp_gpp[sector / f_emu.part_size];
|
||||||
sector = sector % f_emu.part_size;
|
sector = sector % f_emu.part_size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fp_tmp = f_emu.fp_gpp[0];
|
fp_tmp = &f_emu.fp_gpp[0];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FS_EMMC_PARTITION_BOOT1:
|
case FS_EMMC_PARTITION_BOOT1:
|
||||||
fp_tmp = f_emu.fp_boot1;
|
fp_tmp = &f_emu.fp_boot1;
|
||||||
break;
|
break;
|
||||||
case FS_EMMC_PARTITION_BOOT0:
|
case FS_EMMC_PARTITION_BOOT0:
|
||||||
fp_tmp = f_emu.fp_boot0;
|
fp_tmp = &f_emu.fp_boot0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,10 +323,44 @@ static uint64_t emummc_read_write_inner(void *buf, unsigned int sector, unsigned
|
|||||||
; //TODO. Out of range. close stuff and fatal?
|
; //TODO. Out of range. close stuff and fatal?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t res = 0;
|
||||||
if (!is_write)
|
if (!is_write)
|
||||||
return !(f_read(fp_tmp, buf, num_sectors << 9, NULL));
|
res = !(f_read(fp_tmp, buf, num_sectors << 9, NULL));
|
||||||
else
|
else
|
||||||
return !(f_write(fp_tmp, buf, num_sectors << 9, NULL));
|
res = !(f_write(fp_tmp, buf, num_sectors << 9, NULL));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Controller close wrapper
|
||||||
|
uint64_t sdmmc_wrapper_controller_close(int mmc_id)
|
||||||
|
{
|
||||||
|
sdmmc_accessor_t *_this;
|
||||||
|
_this = sdmmc_accessor_get(mmc_id);
|
||||||
|
|
||||||
|
if (_this != NULL)
|
||||||
|
{
|
||||||
|
if (mmc_id == FS_SDMMC_SD)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mmc_id == FS_SDMMC_EMMC)
|
||||||
|
{
|
||||||
|
// Close file handles and unmount
|
||||||
|
_file_based_emmc_finalize();
|
||||||
|
|
||||||
|
// Close SD
|
||||||
|
sdmmc_accessor_get(FS_SDMMC_SD)->vtab->sdmmc_accessor_controller_close(sdmmc_accessor_get(FS_SDMMC_SD));
|
||||||
|
|
||||||
|
// Close eMMC
|
||||||
|
return _this->vtab->sdmmc_accessor_controller_close(_this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _this->vtab->sdmmc_accessor_controller_close(_this);
|
||||||
|
}
|
||||||
|
|
||||||
|
fatal_abort(Fatal_CloseAccessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FS read wrapper.
|
// FS read wrapper.
|
||||||
@@ -366,6 +399,18 @@ uint64_t sdmmc_wrapper_read(void *buf, uint64_t bufSize, int mmc_id, unsigned in
|
|||||||
|
|
||||||
if (mmc_id == FS_SDMMC_SD)
|
if (mmc_id == FS_SDMMC_SD)
|
||||||
{
|
{
|
||||||
|
static bool first_sd_read = true;
|
||||||
|
if (first_sd_read)
|
||||||
|
{
|
||||||
|
first_sd_read = false;
|
||||||
|
// Because some SD cards have issues with emuMMC's driver
|
||||||
|
// we currently swap to FS's driver after first SD read
|
||||||
|
// TODO: Fix remaining driver issues
|
||||||
|
custom_driver = false;
|
||||||
|
// FS will handle sd mutex w/o custom driver from here on
|
||||||
|
unlock_mutex(sd_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
// Call hekates driver.
|
// Call hekates driver.
|
||||||
if (sdmmc_storage_read(&sd_storage, sector, num_sectors, buf))
|
if (sdmmc_storage_read(&sd_storage, sector, num_sectors, buf))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ sdmmc_accessor_t *sdmmc_accessor_get(int mmc_id);
|
|||||||
void mutex_lock_handler(int mmc_id);
|
void mutex_lock_handler(int mmc_id);
|
||||||
void mutex_unlock_handler(int mmc_id);
|
void mutex_unlock_handler(int mmc_id);
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
uint64_t sdmmc_wrapper_controller_close(int mmc_id);
|
||||||
uint64_t sdmmc_wrapper_read(void *buf, uint64_t bufSize, int mmc_id, unsigned int sector, unsigned int num_sectors);
|
uint64_t sdmmc_wrapper_read(void *buf, uint64_t bufSize, int mmc_id, unsigned int sector, unsigned int num_sectors);
|
||||||
uint64_t sdmmc_wrapper_write(int mmc_id, unsigned int sector, unsigned int num_sectors, void *buf, uint64_t bufSize);
|
uint64_t sdmmc_wrapper_write(int mmc_id, unsigned int sector, unsigned int num_sectors, void *buf, uint64_t bufSize);
|
||||||
|
|
||||||
@@ -59,9 +61,9 @@ typedef struct _file_based_ctxt
|
|||||||
uint64_t parts;
|
uint64_t parts;
|
||||||
uint64_t part_size;
|
uint64_t part_size;
|
||||||
FATFS *sd_fs;
|
FATFS *sd_fs;
|
||||||
FIL *fp_boot0;
|
FIL fp_boot0;
|
||||||
FIL *fp_boot1;
|
FIL fp_boot1;
|
||||||
FIL *fp_gpp[32];
|
FIL fp_gpp[32];
|
||||||
} file_based_ctxt;
|
} file_based_ctxt;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "nx/svc.h"
|
#include "nx/svc.h"
|
||||||
#include "nx/smc.h"
|
#include "nx/smc.h"
|
||||||
|
#include "soc/clock.h"
|
||||||
|
#include "soc/i2c.h"
|
||||||
#include "emuMMC/emummc.h"
|
#include "emuMMC/emummc.h"
|
||||||
#include "emuMMC/emummc_ctx.h"
|
#include "emuMMC/emummc_ctx.h"
|
||||||
#include "FS/FS_offsets.h"
|
#include "FS/FS_offsets.h"
|
||||||
@@ -174,6 +176,8 @@ void setup_hooks(void)
|
|||||||
INJECT_HOOK(fs_offsets->sdmmc_wrapper_read, sdmmc_wrapper_read);
|
INJECT_HOOK(fs_offsets->sdmmc_wrapper_read, sdmmc_wrapper_read);
|
||||||
// sdmmc_wrapper_write hook
|
// sdmmc_wrapper_write hook
|
||||||
INJECT_HOOK(fs_offsets->sdmmc_wrapper_write, sdmmc_wrapper_write);
|
INJECT_HOOK(fs_offsets->sdmmc_wrapper_write, sdmmc_wrapper_write);
|
||||||
|
// sdmmc_wrapper_controller_close hook
|
||||||
|
INJECT_HOOK(fs_offsets->sdmmc_accessor_controller_close, sdmmc_wrapper_controller_close);
|
||||||
|
|
||||||
// On 8.0.0+, we need to hook the regulator setup, because
|
// On 8.0.0+, we need to hook the regulator setup, because
|
||||||
// otherwise it will abort because we have already turned it on.
|
// otherwise it will abort because we have already turned it on.
|
||||||
@@ -203,10 +207,6 @@ void populate_function_pointers(void)
|
|||||||
|
|
||||||
void write_nops(void)
|
void write_nops(void)
|
||||||
{
|
{
|
||||||
// This NOPs out a call to ShutdownSdCard when preparing for shutdown/reboot.
|
|
||||||
// This prevents the PatrolReader from hanging when saving its state, which
|
|
||||||
// occurs immediately afterwards (in ShutdownMmc).
|
|
||||||
INJECT_NOP(fs_offsets->shutdown_sd);
|
|
||||||
// On 7.0.0+, we need to attach to device address space ourselves.
|
// On 7.0.0+, we need to attach to device address space ourselves.
|
||||||
// This patches an abort that happens when Nintendo's code sees SD
|
// This patches an abort that happens when Nintendo's code sees SD
|
||||||
// is already attached
|
// is already attached
|
||||||
@@ -316,4 +316,7 @@ void __init()
|
|||||||
populate_function_pointers();
|
populate_function_pointers();
|
||||||
write_nops();
|
write_nops();
|
||||||
setup_nintendo_paths();
|
setup_nintendo_paths();
|
||||||
|
|
||||||
|
clock_enable_i2c5();
|
||||||
|
i2c_init();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,8 @@
|
|||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
#include "t210.h"
|
#include "t210.h"
|
||||||
|
|
||||||
static u32 i2c_addrs[] = {
|
// TODO: not hardcode I2C_5
|
||||||
|
static u64 i2c_addrs[] = {
|
||||||
0x7000C000, 0x7000C400, 0x7000C500,
|
0x7000C000, 0x7000C400, 0x7000C500,
|
||||||
0x7000C700, 0x7000D000, 0x7000D100
|
0x7000C700, 0x7000D000, 0x7000D100
|
||||||
};
|
};
|
||||||
@@ -28,6 +29,7 @@ static u32 i2c_addrs[] = {
|
|||||||
static void _i2c_wait(vu32 *base)
|
static void _i2c_wait(vu32 *base)
|
||||||
{
|
{
|
||||||
base[I2C_CONFIG_LOAD] = 0x25;
|
base[I2C_CONFIG_LOAD] = 0x25;
|
||||||
|
|
||||||
for (u32 i = 0; i < 20; i++)
|
for (u32 i = 0; i < 20; i++)
|
||||||
{
|
{
|
||||||
usleep(1);
|
usleep(1);
|
||||||
@@ -44,8 +46,7 @@ static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size)
|
|||||||
u32 tmp = 0;
|
u32 tmp = 0;
|
||||||
memcpy(&tmp, buf, size);
|
memcpy(&tmp, buf, size);
|
||||||
|
|
||||||
vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[0], 0x2000);
|
vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[I2C_5], 0x1000);
|
||||||
base = base + (i2c_addrs[idx] - i2c_addrs[0]);
|
|
||||||
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
|
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
|
||||||
base[I2C_CMD_DATA1] = tmp; //Set value.
|
base[I2C_CMD_DATA1] = tmp; //Set value.
|
||||||
base[I2C_CNFG] = (2 * size - 2) | 0x2800; //Set size and send mode.
|
base[I2C_CNFG] = (2 * size - 2) | 0x2800; //Set size and send mode.
|
||||||
@@ -66,8 +67,7 @@ static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x)
|
|||||||
if (size > 8)
|
if (size > 8)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[0], 0x2000);
|
vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[I2C_5], 0x1000);
|
||||||
base = base + (i2c_addrs[idx] - i2c_addrs[0]);
|
|
||||||
|
|
||||||
base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode).
|
base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode).
|
||||||
base[I2C_CNFG] = (size - 1) << 1 | 0x2840; // Set size and recv mode.
|
base[I2C_CNFG] = (size - 1) << 1 | 0x2840; // Set size and recv mode.
|
||||||
@@ -93,10 +93,9 @@ static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void i2c_init(u32 idx)
|
void i2c_init()
|
||||||
{
|
{
|
||||||
vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[0], 0x2000);
|
vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[I2C_5], 0x1000);
|
||||||
base = base + (i2c_addrs[idx] - i2c_addrs[0]);
|
|
||||||
|
|
||||||
base[I2C_CLK_DIVISOR_REGISTER] = 0x50001;
|
base[I2C_CLK_DIVISOR_REGISTER] = 0x50001;
|
||||||
base[I2C_BUS_CLEAR_CONFIG] = 0x90003;
|
base[I2C_BUS_CLEAR_CONFIG] = 0x90003;
|
||||||
@@ -104,7 +103,6 @@ void i2c_init(u32 idx)
|
|||||||
|
|
||||||
for (u32 i = 0; i < 10; i++)
|
for (u32 i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
usleep(20000);
|
|
||||||
if (base[INTERRUPT_STATUS_REGISTER] & 0x800)
|
if (base[INTERRUPT_STATUS_REGISTER] & 0x800)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
#define I2C_BUS_CLEAR_STATUS 0x22
|
#define I2C_BUS_CLEAR_STATUS 0x22
|
||||||
#define I2C_CONFIG_LOAD 0x23
|
#define I2C_CONFIG_LOAD 0x23
|
||||||
|
|
||||||
void i2c_init(u32 idx);
|
void i2c_init();
|
||||||
int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size);
|
int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size);
|
||||||
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y);
|
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y);
|
||||||
int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b);
|
int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ enum FatalReason {
|
|||||||
Fatal_UnknownVersion,
|
Fatal_UnknownVersion,
|
||||||
Fatal_BadResult,
|
Fatal_BadResult,
|
||||||
Fatal_GetConfig,
|
Fatal_GetConfig,
|
||||||
|
Fatal_CloseAccessor,
|
||||||
Fatal_Max
|
Fatal_Max
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint6
|
|||||||
/* Treat the path as a folder with each part inside. */
|
/* Treat the path as a folder with each part inside. */
|
||||||
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part);
|
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part);
|
||||||
} else {
|
} else {
|
||||||
target_sector = sector;
|
/* If there are no parts, copy the origin path directly. */
|
||||||
strcpy(target_path, origin_path);
|
strcpy(target_path, origin_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ int emu_device_partition_write_data(device_partition_t *devpart, const void *src
|
|||||||
/* Treat the path as a folder with each part inside. */
|
/* Treat the path as a folder with each part inside. */
|
||||||
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part);
|
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part);
|
||||||
} else {
|
} else {
|
||||||
target_sector = sector;
|
/* If there are no parts, copy the origin path directly. */
|
||||||
strcpy(target_path, origin_path);
|
strcpy(target_path, origin_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ static emudev_device_t *emudev_find_device(const char *name) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int emudev_mount_device(const char *name, const device_partition_t *devpart, const char *origin_path) {
|
int emudev_mount_device(const char *name, const device_partition_t *devpart, const char *origin_path, int num_parts, uint64_t part_limit) {
|
||||||
emudev_device_t *device = NULL;
|
emudev_device_t *device = NULL;
|
||||||
|
|
||||||
if (name[0] == '\0' || devpart == NULL) {
|
if (name[0] == '\0' || devpart == NULL) {
|
||||||
@@ -120,80 +120,6 @@ int emudev_mount_device(const char *name, const device_partition_t *devpart, con
|
|||||||
if (devpart->emu_use_file)
|
if (devpart->emu_use_file)
|
||||||
strcpy(device->origin_path, origin_path);
|
strcpy(device->origin_path, origin_path);
|
||||||
|
|
||||||
device->num_parts = 0;
|
|
||||||
device->part_limit = 0;
|
|
||||||
|
|
||||||
device->devoptab.name = device->name;
|
|
||||||
device->devoptab.deviceData = device;
|
|
||||||
|
|
||||||
/* Initialize immediately. */
|
|
||||||
int rc = device->devpart.initializer(&device->devpart);
|
|
||||||
if (rc != 0) {
|
|
||||||
errno = rc;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate memory for our intermediate sector. */
|
|
||||||
device->tmp_sector = (uint8_t *)malloc(devpart->sector_size);
|
|
||||||
if (device->tmp_sector == NULL) {
|
|
||||||
errno = ENOMEM;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
device->setup = true;
|
|
||||||
device->registered = false;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int emudev_mount_device_multipart(const char *name, const device_partition_t *devpart, const char *origin_path, int num_parts, uint64_t part_limit) {
|
|
||||||
emudev_device_t *device = NULL;
|
|
||||||
|
|
||||||
if (name[0] == '\0' || devpart == NULL) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(name) > 32) {
|
|
||||||
errno = ENAMETOOLONG;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (emudev_find_device(name) != NULL) {
|
|
||||||
errno = EEXIST; /* Device already exists */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Invalid number of parts. */
|
|
||||||
if (num_parts <= 1) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Part limit is invalid. */
|
|
||||||
if ((part_limit % (1ull << 30)) != 0) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find an unused slot. */
|
|
||||||
for (size_t i = 0; i < EMUDEV_MAX_DEVICES; i++) {
|
|
||||||
if (!g_emudev_devices[i].setup) {
|
|
||||||
device = &g_emudev_devices[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (device == NULL) {
|
|
||||||
errno = ENOMEM;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(device, 0, sizeof(emudev_device_t));
|
|
||||||
device->devoptab = g_emudev_devoptab;
|
|
||||||
device->devpart = *devpart;
|
|
||||||
strcpy(device->name, name);
|
|
||||||
strcpy(device->root_path, name);
|
|
||||||
strcat(device->root_path, ":/");
|
|
||||||
strcpy(device->origin_path, origin_path);
|
|
||||||
device->num_parts = num_parts;
|
device->num_parts = num_parts;
|
||||||
device->part_limit = part_limit;
|
device->part_limit = part_limit;
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,7 @@
|
|||||||
|
|
||||||
#define EMUDEV_MAX_DEVICES 16
|
#define EMUDEV_MAX_DEVICES 16
|
||||||
|
|
||||||
int emudev_mount_device(const char *name, const device_partition_t *devpart, const char *origin_path);
|
int emudev_mount_device(const char *name, const device_partition_t *devpart, const char *origin_path, int num_parts, uint64_t part_limit);
|
||||||
int emudev_mount_device_multipart(const char *name, const device_partition_t *devpart, const char *origin_path, int num_parts, uint64_t part_limit);
|
|
||||||
int emudev_register_device(const char *name);
|
int emudev_register_device(const char *name);
|
||||||
int emudev_unregister_device(const char *name);
|
int emudev_unregister_device(const char *name);
|
||||||
int emudev_unmount_device(const char *name); /* also unregisters. */
|
int emudev_unmount_device(const char *name); /* also unregisters. */
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ int gpt_iterate_through_entries(FILE *disk, size_t sector_size, gpt_entry_iterat
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpt_iterate_through_emu_entries(FILE *disk, size_t sector_size, gpt_emu_entry_iterator_t callback, void *param, const char *origin_path, bool is_multipart, int num_parts, uint64_t part_limit) {
|
int gpt_iterate_through_emu_entries(FILE *disk, size_t sector_size, gpt_emu_entry_iterator_t callback, void *param, const char *origin_path, int num_parts, uint64_t part_limit) {
|
||||||
efi_header_t hdr;
|
efi_header_t hdr;
|
||||||
efi_entry_t entry;
|
efi_entry_t entry;
|
||||||
size_t offset = 2 * 512; /* Sector #2. */
|
size_t offset = 2 * 512; /* Sector #2. */
|
||||||
@@ -138,7 +138,7 @@ int gpt_iterate_through_emu_entries(FILE *disk, size_t sector_size, gpt_emu_entr
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callback(&entry, param, offset, disk, origin_path, is_multipart, num_parts, part_limit) != 0) {
|
if (callback(&entry, param, offset, disk, origin_path, num_parts, part_limit) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,10 +52,10 @@ typedef struct efi_header {
|
|||||||
} __attribute__((packed, aligned(4))) efi_header_t;
|
} __attribute__((packed, aligned(4))) efi_header_t;
|
||||||
|
|
||||||
typedef int (*gpt_entry_iterator_t)(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk);
|
typedef int (*gpt_entry_iterator_t)(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk);
|
||||||
typedef int (*gpt_emu_entry_iterator_t)(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk, const char *origin_path, bool is_multipart, int num_parts, uint64_t part_limit);
|
typedef int (*gpt_emu_entry_iterator_t)(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk, const char *origin_path, int num_parts, uint64_t part_limit);
|
||||||
|
|
||||||
int gpt_get_header(efi_header_t *out, FILE *disk, size_t sector_size);
|
int gpt_get_header(efi_header_t *out, FILE *disk, size_t sector_size);
|
||||||
int gpt_iterate_through_entries(FILE *disk, size_t sector_size, gpt_entry_iterator_t callback, void *param);
|
int gpt_iterate_through_entries(FILE *disk, size_t sector_size, gpt_entry_iterator_t callback, void *param);
|
||||||
int gpt_iterate_through_emu_entries(FILE *disk, size_t sector_size, gpt_emu_entry_iterator_t callback, void *param, const char *origin_path, bool is_multipart, int num_parts, uint64_t part_limit);
|
int gpt_iterate_through_emu_entries(FILE *disk, size_t sector_size, gpt_emu_entry_iterator_t callback, void *param, const char *origin_path, int num_parts, uint64_t part_limit);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -223,7 +223,14 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
||||||
emummc_config_t emummc_cfg = {.enabled = false, .id = 0, .sector = -1, .path = "", .nintendo_path = ""};
|
emummc_config_t emummc_cfg = {.enabled = false, .id = 0, .sector = 0, .path = "", .nintendo_path = ""};
|
||||||
|
|
||||||
|
/* Initialize some defaults. */
|
||||||
|
memset(exo_emummc_config, 0, sizeof(*exo_emummc_config));
|
||||||
|
exo_emummc_config->base_cfg.magic = MAGIC_EMUMMC_CONFIG;
|
||||||
|
exo_emummc_config->base_cfg.type = EMUMMC_TYPE_NONE;
|
||||||
|
exo_emummc_config->base_cfg.id = 0;
|
||||||
|
exo_emummc_config->base_cfg.fs_version = FS_VER_1_0_0; /* Will be filled out later. */
|
||||||
|
|
||||||
char *emummc_ini = calloc(1, 0x10000);
|
char *emummc_ini = calloc(1, 0x10000);
|
||||||
if (!read_from_file(emummc_ini, 0xFFFF, "emummc/emummc.ini")) {
|
if (!read_from_file(emummc_ini, 0xFFFF, "emummc/emummc.ini")) {
|
||||||
@@ -238,16 +245,13 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
|||||||
|
|
||||||
free(emummc_ini);
|
free(emummc_ini);
|
||||||
|
|
||||||
memset(exo_emummc_config, 0, sizeof(*exo_emummc_config));
|
/* Initialize values from emummc config. */
|
||||||
exo_emummc_config->base_cfg.magic = MAGIC_EMUMMC_CONFIG;
|
|
||||||
exo_emummc_config->base_cfg.type = EMUMMC_TYPE_NONE;
|
|
||||||
exo_emummc_config->base_cfg.id = emummc_cfg.id;
|
exo_emummc_config->base_cfg.id = emummc_cfg.id;
|
||||||
exo_emummc_config->base_cfg.fs_version = FS_VER_1_0_0; /* Will be filled out later. */
|
|
||||||
strncpy(exo_emummc_config->emu_dir_path, emummc_cfg.nintendo_path, sizeof(exo_emummc_config->emu_dir_path));
|
strncpy(exo_emummc_config->emu_dir_path, emummc_cfg.nintendo_path, sizeof(exo_emummc_config->emu_dir_path));
|
||||||
exo_emummc_config->emu_dir_path[sizeof(exo_emummc_config->emu_dir_path) - 1] = '\0';
|
exo_emummc_config->emu_dir_path[sizeof(exo_emummc_config->emu_dir_path) - 1] = '\0';
|
||||||
|
|
||||||
if (emummc_cfg.enabled) {
|
if (emummc_cfg.enabled) {
|
||||||
if (emummc_cfg.sector != -1) {
|
if (emummc_cfg.sector > 0) {
|
||||||
exo_emummc_config->base_cfg.type = EMUMMC_TYPE_PARTITION;
|
exo_emummc_config->base_cfg.type = EMUMMC_TYPE_PARTITION;
|
||||||
exo_emummc_config->partition_cfg.start_sector = emummc_cfg.sector;
|
exo_emummc_config->partition_cfg.start_sector = emummc_cfg.sector;
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,11 @@
|
|||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#define EMUMMC_ENABLED_KEY "emummc_enabled"
|
#define EMUMMC_ENABLED_KEY "enabled"
|
||||||
#define EMUMMC_SECTOR_KEY "emummc_sector"
|
#define EMUMMC_SECTOR_KEY "sector"
|
||||||
#define EMUMMC_PATH_KEY "emummc_path"
|
#define EMUMMC_PATH_KEY "path"
|
||||||
#define EMUMMC_NINTENDO_PATH_KEY "emummc_nintendo_path"
|
#define EMUMMC_NINTENDO_PATH_KEY "nintendo_path"
|
||||||
#define EMUMMC_ID_KEY "emummc_id"
|
#define EMUMMC_ID_KEY "id"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
|||||||
@@ -352,7 +352,7 @@ static int nxfs_mount_partition_gpt_callback(const efi_entry_t *entry, void *par
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nxfs_mount_emu_partition_gpt_callback(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk, const char *origin_path, bool is_multipart, int num_parts, uint64_t part_limit) {
|
static int nxfs_mount_emu_partition_gpt_callback(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk, const char *origin_path, int num_parts, uint64_t part_limit) {
|
||||||
(void)entry_offset;
|
(void)entry_offset;
|
||||||
(void)disk;
|
(void)disk;
|
||||||
device_partition_t *parent = (device_partition_t *)param;
|
device_partition_t *parent = (device_partition_t *)param;
|
||||||
@@ -416,16 +416,9 @@ static int nxfs_mount_emu_partition_gpt_callback(const efi_entry_t *entry, void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_multipart) {
|
rc = emudev_mount_device(known_partitions[i].mount_point, &devpart, origin_path, num_parts, part_limit);
|
||||||
rc = emudev_mount_device_multipart(known_partitions[i].mount_point, &devpart, origin_path, num_parts, part_limit);
|
if (rc == -1) {
|
||||||
if (rc == -1) {
|
return -1;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rc = emudev_mount_device(known_partitions[i].mount_point, &devpart, origin_path);
|
|
||||||
if (rc == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (known_partitions[i].register_immediately) {
|
if (known_partitions[i].register_immediately) {
|
||||||
rc = emudev_register_device(known_partitions[i].mount_point);
|
rc = emudev_register_device(known_partitions[i].mount_point);
|
||||||
@@ -564,7 +557,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
|||||||
model.emu_use_file = false;
|
model.emu_use_file = false;
|
||||||
|
|
||||||
/* Mount emulated boot0 device. */
|
/* Mount emulated boot0 device. */
|
||||||
rc = emudev_mount_device("boot0", &model, NULL);
|
rc = emudev_mount_device("boot0", &model, NULL, 0, 0);
|
||||||
|
|
||||||
/* Failed to mount boot0 device. */
|
/* Failed to mount boot0 device. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
@@ -586,7 +579,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
|||||||
model.emu_use_file = false;
|
model.emu_use_file = false;
|
||||||
|
|
||||||
/* Mount emulated boot1 device. */
|
/* Mount emulated boot1 device. */
|
||||||
rc = emudev_mount_device("boot1", &model, NULL);
|
rc = emudev_mount_device("boot1", &model, NULL, 0, 0);
|
||||||
|
|
||||||
/* Failed to mount boot1. */
|
/* Failed to mount boot1. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
@@ -602,7 +595,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
|||||||
model.emu_use_file = false;
|
model.emu_use_file = false;
|
||||||
|
|
||||||
/* Mount emulated raw NAND device. */
|
/* Mount emulated raw NAND device. */
|
||||||
rc = emudev_mount_device("rawnand", &model, NULL);
|
rc = emudev_mount_device("rawnand", &model, NULL, 0, 0);
|
||||||
|
|
||||||
/* Failed to mount raw NAND. */
|
/* Failed to mount raw NAND. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
@@ -626,7 +619,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate the GPT and mount each emulated raw NAND partition. */
|
/* Iterate the GPT and mount each emulated raw NAND partition. */
|
||||||
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, NULL, false, 0, 0);
|
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, NULL, 0, 0);
|
||||||
|
|
||||||
/* Close emulated raw NAND device. */
|
/* Close emulated raw NAND device. */
|
||||||
fclose(rawnand);
|
fclose(rawnand);
|
||||||
@@ -647,7 +640,6 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
|||||||
bool is_exfat;
|
bool is_exfat;
|
||||||
char emummc_boot0_path[0x300 + 1] = {0};
|
char emummc_boot0_path[0x300 + 1] = {0};
|
||||||
char emummc_boot1_path[0x300 + 1] = {0};
|
char emummc_boot1_path[0x300 + 1] = {0};
|
||||||
char emummc_rawnand_path[0x300 + 1] = {0};
|
|
||||||
|
|
||||||
/* Check if the SD card is EXFAT formatted. */
|
/* Check if the SD card is EXFAT formatted. */
|
||||||
rc = fsdev_is_exfat("sdmc");
|
rc = fsdev_is_exfat("sdmc");
|
||||||
@@ -660,17 +652,22 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
|||||||
/* Set EXFAT status. */
|
/* Set EXFAT status. */
|
||||||
is_exfat = (rc == 1);
|
is_exfat = (rc == 1);
|
||||||
|
|
||||||
|
/* Reject single part in FAT32. */
|
||||||
|
if (!is_exfat && (num_parts <= 1)) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
/* We want a folder with the archive bit set. */
|
/* We want a folder with the archive bit set. */
|
||||||
rc = fsdev_get_attr(emummc_path);
|
rc = fsdev_get_attr(emummc_path);
|
||||||
|
|
||||||
/* Failed to get file DOS attributes. */
|
/* Failed to get file DOS attributes. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Our path is not a directory. */
|
/* Our path is not a directory. */
|
||||||
if (!(rc & AM_DIR)) {
|
if (!(rc & AM_DIR)) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the archive bit is not set. */
|
/* Check if the archive bit is not set. */
|
||||||
@@ -680,7 +677,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
|||||||
|
|
||||||
/* Failed to set file DOS attributes. */
|
/* Failed to set file DOS attributes. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -694,11 +691,11 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
|||||||
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0");
|
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0");
|
||||||
|
|
||||||
/* Mount emulated boot0 device. */
|
/* Mount emulated boot0 device. */
|
||||||
rc = emudev_mount_device("boot0", &model, emummc_boot0_path);
|
rc = emudev_mount_device("boot0", &model, emummc_boot0_path, 0, 0);
|
||||||
|
|
||||||
/* Failed to mount boot0 device. */
|
/* Failed to mount boot0 device. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register emulated boot0 device. */
|
/* Register emulated boot0 device. */
|
||||||
@@ -706,7 +703,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
|||||||
|
|
||||||
/* Failed to register boot0 device. */
|
/* Failed to register boot0 device. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup an emulation template for boot1. */
|
/* Setup an emulation template for boot1. */
|
||||||
@@ -719,11 +716,11 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
|||||||
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1");
|
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1");
|
||||||
|
|
||||||
/* Mount emulated boot1 device. */
|
/* Mount emulated boot1 device. */
|
||||||
rc = emudev_mount_device("boot1", &model, emummc_boot1_path);
|
rc = emudev_mount_device("boot1", &model, emummc_boot1_path, 0, 0);
|
||||||
|
|
||||||
/* Failed to mount boot1. */
|
/* Failed to mount boot1. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register emulated boot1 device. */
|
/* Register emulated boot1 device. */
|
||||||
@@ -731,7 +728,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
|||||||
|
|
||||||
/* Failed to register boot1 device. */
|
/* Failed to register boot1 device. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -9;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup a template for raw NAND. */
|
/* Setup a template for raw NAND. */
|
||||||
@@ -740,19 +737,12 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
|||||||
model.num_sectors = (256ull << 30) / model.sector_size;
|
model.num_sectors = (256ull << 30) / model.sector_size;
|
||||||
model.emu_use_file = true;
|
model.emu_use_file = true;
|
||||||
|
|
||||||
/* Prepare single raw NAND file path. */
|
|
||||||
snprintf(emummc_rawnand_path, sizeof(emummc_rawnand_path) - 1, "%s/%02d", emummc_path, 0);
|
|
||||||
|
|
||||||
/* Mount emulated raw NAND device from single or multiple parts. */
|
/* Mount emulated raw NAND device from single or multiple parts. */
|
||||||
if (!is_exfat) {
|
rc = emudev_mount_device("rawnand", &model, emummc_path, num_parts, part_limit);
|
||||||
rc = emudev_mount_device_multipart("rawnand", &model, emummc_path, num_parts, part_limit);
|
|
||||||
} else {
|
|
||||||
rc = emudev_mount_device("rawnand", &model, emummc_rawnand_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Failed to mount raw NAND. */
|
/* Failed to mount raw NAND. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -10;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register emulated raw NAND device. */
|
/* Register emulated raw NAND device. */
|
||||||
@@ -760,7 +750,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
|||||||
|
|
||||||
/* Failed to register raw NAND device. */
|
/* Failed to register raw NAND device. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -11;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open emulated raw NAND device. */
|
/* Open emulated raw NAND device. */
|
||||||
@@ -768,15 +758,11 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
|||||||
|
|
||||||
/* Failed to open emulated raw NAND device. */
|
/* Failed to open emulated raw NAND device. */
|
||||||
if (rawnand == NULL) {
|
if (rawnand == NULL) {
|
||||||
return -1;
|
return -12;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate the GPT and mount each emulated raw NAND partition. */
|
/* Iterate the GPT and mount each emulated raw NAND partition. */
|
||||||
if (!is_exfat) {
|
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emummc_path, num_parts, part_limit);
|
||||||
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emummc_path, true, num_parts, part_limit);
|
|
||||||
} else {
|
|
||||||
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emummc_rawnand_path, false, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close emulated raw NAND device. */
|
/* Close emulated raw NAND device. */
|
||||||
fclose(rawnand);
|
fclose(rawnand);
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ _content_headers:
|
|||||||
.word __sept_secondary_00_enc_size__
|
.word __sept_secondary_00_enc_size__
|
||||||
.word CONTENT_TYPE_SP2
|
.word CONTENT_TYPE_SP2
|
||||||
.word 0xCCCCCCCC
|
.word 0xCCCCCCCC
|
||||||
.asciz "sept_secondary_00"
|
.asciz "septsecondary00"
|
||||||
.align 5
|
.align 5
|
||||||
|
|
||||||
/* sept_secondary 01 content header */
|
/* sept_secondary 01 content header */
|
||||||
@@ -181,7 +181,7 @@ _content_headers:
|
|||||||
.word __sept_secondary_01_enc_size__
|
.word __sept_secondary_01_enc_size__
|
||||||
.word CONTENT_TYPE_SP2
|
.word CONTENT_TYPE_SP2
|
||||||
.word 0xCCCCCCCC
|
.word 0xCCCCCCCC
|
||||||
.asciz "sept_secondary_01"
|
.asciz "septsecondary01"
|
||||||
.align 5
|
.align 5
|
||||||
|
|
||||||
/* sm content header */
|
/* sm content header */
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ DATA := data
|
|||||||
INCLUDES := include ../../common/include
|
INCLUDES := include ../../common/include
|
||||||
EXEFS_SRC := exefs_src
|
EXEFS_SRC := exefs_src
|
||||||
|
|
||||||
DEFINES := -DDISABLE_IPC -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\"
|
DEFINES := -DRESULT_ABORT_ON_ASSERT -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\"
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# options for code generation
|
# options for code generation
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -34,7 +34,7 @@ extern "C" {
|
|||||||
#define INNER_HEAP_SIZE 0x1000000
|
#define INNER_HEAP_SIZE 0x1000000
|
||||||
size_t nx_inner_heap_size = INNER_HEAP_SIZE;
|
size_t nx_inner_heap_size = INNER_HEAP_SIZE;
|
||||||
char nx_inner_heap[INNER_HEAP_SIZE];
|
char nx_inner_heap[INNER_HEAP_SIZE];
|
||||||
|
|
||||||
void __libnx_initheap(void);
|
void __libnx_initheap(void);
|
||||||
void __appInit(void);
|
void __appInit(void);
|
||||||
void __appExit(void);
|
void __appExit(void);
|
||||||
@@ -69,27 +69,14 @@ void __libnx_initheap(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void __appInit(void) {
|
void __appInit(void) {
|
||||||
Result rc;
|
|
||||||
|
|
||||||
SetFirmwareVersionForLibnx();
|
SetFirmwareVersionForLibnx();
|
||||||
|
|
||||||
DoWithSmSession([&]() {
|
DoWithSmSession([&]() {
|
||||||
rc = fsInitialize();
|
R_ASSERT(fsInitialize());
|
||||||
if (R_FAILED(rc)) {
|
R_ASSERT(pmdmntInitialize());
|
||||||
std::abort();
|
R_ASSERT(pminfoInitialize());
|
||||||
}
|
|
||||||
|
|
||||||
rc = pmdmntInitialize();
|
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = pminfoInitialize();
|
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION);
|
CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,19 +89,15 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
consoleDebugInit(debugDevice_SVC);
|
consoleDebugInit(debugDevice_SVC);
|
||||||
HosThread initializer_thread;
|
HosThread initializer_thread;
|
||||||
|
|
||||||
LaunchAllMitmModules();
|
LaunchAllMitmModules();
|
||||||
|
|
||||||
if (R_FAILED(initializer_thread.Initialize(&Utils::InitializeThreadFunc, NULL, 0x4000, 0x15))) {
|
R_ASSERT(initializer_thread.Initialize(&Utils::InitializeThreadFunc, NULL, 0x4000, 0x15));
|
||||||
std::abort();
|
R_ASSERT(initializer_thread.Start());
|
||||||
}
|
|
||||||
if (R_FAILED(initializer_thread.Start())) {
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wait for all mitm modules to end. */
|
/* Wait for all mitm modules to end. */
|
||||||
WaitAllMitmModules();
|
WaitAllMitmModules();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -43,16 +43,12 @@ void LaunchAllMitmModules() {
|
|||||||
/* Create thread for each module. */
|
/* Create thread for each module. */
|
||||||
for (u32 i = 0; i < static_cast<u32>(MitmModuleId_Count); i++) {
|
for (u32 i = 0; i < static_cast<u32>(MitmModuleId_Count); i++) {
|
||||||
const auto cur_module = &g_module_definitions[i];
|
const auto cur_module = &g_module_definitions[i];
|
||||||
if (R_FAILED(g_module_threads[i].Initialize(cur_module->main, nullptr, cur_module->stack_size, cur_module->priority))) {
|
R_ASSERT(g_module_threads[i].Initialize(cur_module->main, nullptr, cur_module->stack_size, cur_module->priority));
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start thread for each module. */
|
/* Start thread for each module. */
|
||||||
for (u32 i = 0; i < static_cast<u32>(MitmModuleId_Count); i++) {
|
for (u32 i = 0; i < static_cast<u32>(MitmModuleId_Count); i++) {
|
||||||
if (R_FAILED(g_module_threads[i].Start())) {
|
R_ASSERT(g_module_threads[i].Start());
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
enum MitmModuleId : u32 {
|
enum MitmModuleId : u32 {
|
||||||
@@ -21,7 +21,7 @@ enum MitmModuleId : u32 {
|
|||||||
MitmModuleId_SetMitm = 1,
|
MitmModuleId_SetMitm = 1,
|
||||||
MitmModuleId_BpcMitm = 2,
|
MitmModuleId_BpcMitm = 2,
|
||||||
MitmModuleId_NsMitm = 3,
|
MitmModuleId_NsMitm = 3,
|
||||||
|
|
||||||
/* Always keep this at the end. */
|
/* Always keep this at the end. */
|
||||||
MitmModuleId_Count,
|
MitmModuleId_Count,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ Result BpcAtmosphereService::RebootToFatalError(InBuffer<AtmosphereFatalErrorCon
|
|||||||
if (ctx.buffer == nullptr || ctx.num_elements != 1) {
|
if (ctx.buffer == nullptr || ctx.num_elements != 1) {
|
||||||
return ResultKernelConnectionClosed;
|
return ResultKernelConnectionClosed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reboot to fusee with the input context. */
|
/* Reboot to fusee with the input context. */
|
||||||
BpcRebootManager::RebootForFatalError(ctx.buffer);
|
BpcRebootManager::RebootForFatalError(ctx.buffer);
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,22 +13,21 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "../utils.hpp"
|
#include "../utils.hpp"
|
||||||
|
|
||||||
enum BpcAtmosphereCmd : u32 {
|
|
||||||
BpcAtmosphereCmd_RebootToFatalError = 65000,
|
|
||||||
};
|
|
||||||
|
|
||||||
class BpcAtmosphereService : public IServiceObject {
|
class BpcAtmosphereService : public IServiceObject {
|
||||||
|
enum class CommandId {
|
||||||
|
RebootToFatalError = 65000,
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
Result RebootToFatalError(InBuffer<AtmosphereFatalErrorContext> ctx);
|
Result RebootToFatalError(InBuffer<AtmosphereFatalErrorContext> ctx);
|
||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MakeServiceCommandMeta<BpcAtmosphereCmd_RebootToFatalError, &BpcAtmosphereService::RebootToFatalError>(),
|
MAKE_SERVICE_COMMAND_META(BpcAtmosphereService, RebootToFatalError),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,24 +13,24 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "../utils.hpp"
|
#include "../utils.hpp"
|
||||||
|
|
||||||
enum BpcCmd : u32 {
|
|
||||||
BpcCmd_ShutdownSystem = 0,
|
|
||||||
BpcCmd_RebootSystem = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
class BpcMitmService : public IMitmServiceObject {
|
class BpcMitmService : public IMitmServiceObject {
|
||||||
|
private:
|
||||||
|
enum class CommandId {
|
||||||
|
ShutdownSystem = 0,
|
||||||
|
RebootSystem = 1,
|
||||||
|
};
|
||||||
public:
|
public:
|
||||||
BpcMitmService(std::shared_ptr<Service> s, u64 pid) : IMitmServiceObject(s, pid) {
|
BpcMitmService(std::shared_ptr<Service> s, u64 pid) : IMitmServiceObject(s, pid) {
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ShouldMitm(u64 pid, u64 tid) {
|
static bool ShouldMitm(u64 pid, u64 tid) {
|
||||||
/* We will mitm:
|
/* We will mitm:
|
||||||
* - am, to intercept the Reboot/Power buttons in the overlay menu.
|
* - am, to intercept the Reboot/Power buttons in the overlay menu.
|
||||||
@@ -39,16 +39,16 @@ class BpcMitmService : public IMitmServiceObject {
|
|||||||
*/
|
*/
|
||||||
return tid == TitleId_Am || tid == TitleId_Fatal || TitleIdIsApplication(tid) || Utils::IsHblTid(tid);
|
return tid == TitleId_Am || tid == TitleId_Fatal || TitleIdIsApplication(tid) || Utils::IsHblTid(tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx);
|
static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* Overridden commands. */
|
/* Overridden commands. */
|
||||||
Result ShutdownSystem();
|
Result ShutdownSystem();
|
||||||
Result RebootSystem();
|
Result RebootSystem();
|
||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MakeServiceCommandMeta<BpcCmd_ShutdownSystem, &BpcMitmService::ShutdownSystem>(),
|
MAKE_SERVICE_COMMAND_META(BpcMitmService, ShutdownSystem),
|
||||||
MakeServiceCommandMeta<BpcCmd_RebootSystem, &BpcMitmService::RebootSystem>(),
|
MAKE_SERVICE_COMMAND_META(BpcMitmService, RebootSystem),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -33,28 +33,25 @@
|
|||||||
void BpcMitmMain(void *arg) {
|
void BpcMitmMain(void *arg) {
|
||||||
/* Wait for initialization to occur */
|
/* Wait for initialization to occur */
|
||||||
Utils::WaitSdInitialized();
|
Utils::WaitSdInitialized();
|
||||||
|
|
||||||
/* Load a payload off of the SD */
|
/* Load a payload off of the SD */
|
||||||
BpcRebootManager::Initialize();
|
BpcRebootManager::Initialize();
|
||||||
|
|
||||||
/* Create server manager */
|
/* Create server manager */
|
||||||
auto server_manager = new WaitableManager(2);
|
static auto s_server_manager = WaitableManager(2);
|
||||||
|
|
||||||
/* Create bpc mitm. */
|
/* Create bpc mitm. */
|
||||||
const char *service_name = "bpc";
|
const char *service_name = "bpc";
|
||||||
if (GetRuntimeFirmwareVersion() < FirmwareVersion_200) {
|
if (GetRuntimeFirmwareVersion() < FirmwareVersion_200) {
|
||||||
service_name = "bpc:c";
|
service_name = "bpc:c";
|
||||||
}
|
}
|
||||||
AddMitmServerToManager<BpcMitmService>(server_manager, service_name, 13);
|
AddMitmServerToManager<BpcMitmService>(&s_server_manager, service_name, 13);
|
||||||
|
|
||||||
/* Extension: Allow for reboot-to-error. */
|
/* Extension: Allow for reboot-to-error. */
|
||||||
/* Must be managed port in order for sm to be able to access. */
|
/* Must be managed port in order for sm to be able to access. */
|
||||||
server_manager->AddWaitable(new ManagedPortServer<BpcAtmosphereService>("bpc:ams", 1));
|
s_server_manager.AddWaitable(new ManagedPortServer<BpcAtmosphereService>("bpc:ams", 1));
|
||||||
|
|
||||||
/* Loop forever, servicing our services. */
|
/* Loop forever, servicing our services. */
|
||||||
server_manager->Process();
|
s_server_manager.Process();
|
||||||
|
|
||||||
delete server_manager;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
@@ -33,16 +33,16 @@ void BpcRebootManager::Initialize() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ON_SCOPE_EXIT { fsFileClose(&payload_file); };
|
ON_SCOPE_EXIT { fsFileClose(&payload_file); };
|
||||||
|
|
||||||
/* Clear payload buffer */
|
/* Clear payload buffer */
|
||||||
std::memset(g_reboot_payload, 0xFF, sizeof(g_reboot_payload));
|
std::memset(g_reboot_payload, 0xFF, sizeof(g_reboot_payload));
|
||||||
|
|
||||||
/* Read payload file. */
|
/* Read payload file. */
|
||||||
size_t actual_size;
|
size_t actual_size;
|
||||||
fsFileRead(&payload_file, 0, g_reboot_payload, IRAM_PAYLOAD_MAX_SIZE, FS_READOPTION_NONE, &actual_size);
|
fsFileRead(&payload_file, 0, g_reboot_payload, IRAM_PAYLOAD_MAX_SIZE, FS_READOPTION_NONE, &actual_size);
|
||||||
|
|
||||||
g_payload_loaded = true;
|
g_payload_loaded = true;
|
||||||
|
|
||||||
/* Figure out what kind of reboot we're gonna be doing. */
|
/* Figure out what kind of reboot we're gonna be doing. */
|
||||||
{
|
{
|
||||||
char reboot_type[0x40] = {0};
|
char reboot_type[0x40] = {0};
|
||||||
@@ -62,7 +62,7 @@ void BpcRebootManager::Initialize() {
|
|||||||
static void ClearIram() {
|
static void ClearIram() {
|
||||||
/* Make page FFs. */
|
/* Make page FFs. */
|
||||||
memset(g_work_page, 0xFF, sizeof(g_work_page));
|
memset(g_work_page, 0xFF, sizeof(g_work_page));
|
||||||
|
|
||||||
/* Overwrite all of IRAM with FFs. */
|
/* Overwrite all of IRAM with FFs. */
|
||||||
for (size_t ofs = 0; ofs < IRAM_SIZE; ofs += sizeof(g_work_page)) {
|
for (size_t ofs = 0; ofs < IRAM_SIZE; ofs += sizeof(g_work_page)) {
|
||||||
CopyToIram(IRAM_BASE + ofs, g_work_page, sizeof(g_work_page));
|
CopyToIram(IRAM_BASE + ofs, g_work_page, sizeof(g_work_page));
|
||||||
@@ -74,15 +74,15 @@ static void DoRebootToPayload() {
|
|||||||
if (!g_payload_loaded) {
|
if (!g_payload_loaded) {
|
||||||
RebootToRcm();
|
RebootToRcm();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure clean IRAM state. */
|
/* Ensure clean IRAM state. */
|
||||||
ClearIram();
|
ClearIram();
|
||||||
|
|
||||||
/* Copy in payload. */
|
/* Copy in payload. */
|
||||||
for (size_t ofs = 0; ofs < sizeof(g_reboot_payload); ofs += 0x1000) {
|
for (size_t ofs = 0; ofs < sizeof(g_reboot_payload); ofs += 0x1000) {
|
||||||
CopyToIram(IRAM_PAYLOAD_BASE + ofs, &g_reboot_payload[ofs], 0x1000);
|
CopyToIram(IRAM_PAYLOAD_BASE + ofs, &g_reboot_payload[ofs], 0x1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
RebootToIramPayload();
|
RebootToIramPayload();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,16 +103,16 @@ Result BpcRebootManager::PerformReboot() {
|
|||||||
void BpcRebootManager::RebootForFatalError(AtmosphereFatalErrorContext *ctx) {
|
void BpcRebootManager::RebootForFatalError(AtmosphereFatalErrorContext *ctx) {
|
||||||
/* Ensure clean IRAM state. */
|
/* Ensure clean IRAM state. */
|
||||||
ClearIram();
|
ClearIram();
|
||||||
|
|
||||||
|
|
||||||
/* Copy in payload. */
|
/* Copy in payload. */
|
||||||
for (size_t ofs = 0; ofs < sizeof(g_reboot_payload); ofs += 0x1000) {
|
for (size_t ofs = 0; ofs < sizeof(g_reboot_payload); ofs += 0x1000) {
|
||||||
CopyToIram(IRAM_PAYLOAD_BASE + ofs, &g_reboot_payload[ofs], 0x1000);
|
CopyToIram(IRAM_PAYLOAD_BASE + ofs, &g_reboot_payload[ofs], 0x1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(g_work_page, ctx, sizeof(*ctx));
|
memcpy(g_work_page, ctx, sizeof(*ctx));
|
||||||
CopyToIram(IRAM_PAYLOAD_BASE + IRAM_PAYLOAD_MAX_SIZE, g_work_page, sizeof(g_work_page));
|
CopyToIram(IRAM_PAYLOAD_BASE + IRAM_PAYLOAD_MAX_SIZE, g_work_page, sizeof(g_work_page));
|
||||||
|
|
||||||
/* If we don't actually have a payload loaded, just go to RCM. */
|
/* If we don't actually have a payload loaded, just go to RCM. */
|
||||||
if (!g_payload_loaded) {
|
if (!g_payload_loaded) {
|
||||||
RebootToRcm();
|
RebootToRcm();
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
void Reboot();
|
void Reboot();
|
||||||
|
|||||||
@@ -21,15 +21,12 @@
|
|||||||
#include "fs_ifile.hpp"
|
#include "fs_ifile.hpp"
|
||||||
|
|
||||||
Result FsDirUtils::CopyFile(IFileSystem *dst_fs, IFileSystem *src_fs, const FsPath &dst_parent_path, const FsPath &src_path, const FsDirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) {
|
Result FsDirUtils::CopyFile(IFileSystem *dst_fs, IFileSystem *src_fs, const FsPath &dst_parent_path, const FsPath &src_path, const FsDirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) {
|
||||||
Result rc;
|
|
||||||
std::unique_ptr<IFile> src_file;
|
std::unique_ptr<IFile> src_file;
|
||||||
std::unique_ptr<IFile> dst_file;
|
std::unique_ptr<IFile> dst_file;
|
||||||
const u64 file_size = dir_ent->fileSize;
|
const u64 file_size = dir_ent->fileSize;
|
||||||
|
|
||||||
/* Open source file for reading. */
|
/* Open source file for reading. */
|
||||||
if (R_FAILED((rc = src_fs->OpenFile(src_file, src_path, OpenMode_Read)))) {
|
R_TRY(src_fs->OpenFile(src_file, src_path, OpenMode_Read));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create and open destination file. */
|
/* Create and open destination file. */
|
||||||
{
|
{
|
||||||
@@ -39,24 +36,16 @@ Result FsDirUtils::CopyFile(IFileSystem *dst_fs, IFileSystem *src_fs, const FsPa
|
|||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_FAILED((rc = dst_fs->CreateFile(dst_path, file_size)))) {
|
R_TRY(dst_fs->CreateFile(dst_path, file_size));
|
||||||
return rc;
|
R_TRY(dst_fs->OpenFile(dst_file, dst_path, OpenMode_Write));
|
||||||
}
|
|
||||||
if (R_FAILED((rc = dst_fs->OpenFile(dst_file, dst_path, OpenMode_Write)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read/Write work_buf_size chunks. */
|
/* Read/Write work_buf_size chunks. */
|
||||||
u64 offset = 0;
|
u64 offset = 0;
|
||||||
while (offset < file_size) {
|
while (offset < file_size) {
|
||||||
u64 read_size;
|
u64 read_size;
|
||||||
if (R_FAILED((rc = src_file->Read(&read_size, offset, work_buf, work_buf_size)))) {
|
R_TRY(src_file->Read(&read_size, offset, work_buf, work_buf_size));
|
||||||
return rc;
|
R_TRY(dst_file->Write(offset, work_buf, read_size));
|
||||||
}
|
|
||||||
if (R_FAILED((rc = dst_file->Write(offset, work_buf, read_size)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += read_size;
|
offset += read_size;
|
||||||
}
|
}
|
||||||
@@ -99,12 +88,9 @@ Result FsDirUtils::CopyDirectoryRecursively(IFileSystem *dst_fs, IFileSystem *sr
|
|||||||
Result FsDirUtils::EnsureDirectoryExists(IFileSystem *fs, const FsPath &path) {
|
Result FsDirUtils::EnsureDirectoryExists(IFileSystem *fs, const FsPath &path) {
|
||||||
FsPath normal_path;
|
FsPath normal_path;
|
||||||
size_t normal_path_len;
|
size_t normal_path_len;
|
||||||
Result rc;
|
|
||||||
|
|
||||||
/* Normalize the path. */
|
/* Normalize the path. */
|
||||||
if (R_FAILED((rc = FsPathUtils::Normalize(normal_path.str, sizeof(normal_path.str) - 1, path.str, &normal_path_len)))) {
|
R_TRY(FsPathUtils::Normalize(normal_path.str, sizeof(normal_path.str) - 1, path.str, &normal_path_len));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Repeatedly call CreateDirectory on each directory leading to the target. */
|
/* Repeatedly call CreateDirectory on each directory leading to the target. */
|
||||||
for (size_t i = 1; i < normal_path_len; i++) {
|
for (size_t i = 1; i < normal_path_len; i++) {
|
||||||
@@ -112,22 +98,22 @@ Result FsDirUtils::EnsureDirectoryExists(IFileSystem *fs, const FsPath &path) {
|
|||||||
if (normal_path.str[i] == '/') {
|
if (normal_path.str[i] == '/') {
|
||||||
normal_path.str[i] = 0;
|
normal_path.str[i] = 0;
|
||||||
{
|
{
|
||||||
rc = fs->CreateDirectory(normal_path);
|
R_TRY_CATCH(fs->CreateDirectory(normal_path)) {
|
||||||
if (rc == ResultFsPathAlreadyExists) {
|
R_CATCH(ResultFsPathAlreadyExists) {
|
||||||
rc = ResultSuccess;
|
/* If path already exists, there's no problem. */
|
||||||
}
|
}
|
||||||
if (R_FAILED(rc)) {
|
} R_END_TRY_CATCH;
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
normal_path.str[i] = '/';
|
normal_path.str[i] = '/';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call CreateDirectory on the final path. */
|
/* Call CreateDirectory on the final path. */
|
||||||
rc = fs->CreateDirectory(normal_path);
|
R_TRY_CATCH(fs->CreateDirectory(normal_path)) {
|
||||||
if (rc == ResultFsPathAlreadyExists) {
|
R_CATCH(ResultFsPathAlreadyExists) {
|
||||||
rc = ResultSuccess;
|
/* If path already exists, there's no problem. */
|
||||||
}
|
}
|
||||||
return rc;
|
} R_END_TRY_CATCH;
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,10 @@ class FsDirUtils {
|
|||||||
private:
|
private:
|
||||||
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
|
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
|
||||||
static Result IterateDirectoryRecursivelyInternal(IFileSystem *fs, FsPath &work_path, FsDirectoryEntry *ent_buf, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
|
static Result IterateDirectoryRecursivelyInternal(IFileSystem *fs, FsPath &work_path, FsDirectoryEntry *ent_buf, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
|
||||||
Result rc;
|
|
||||||
std::unique_ptr<IDirectory> dir;
|
std::unique_ptr<IDirectory> dir;
|
||||||
|
|
||||||
/* Open the directory. */
|
/* Open the directory. */
|
||||||
if (R_FAILED((rc = fs->OpenDirectory(dir, work_path, DirectoryOpenMode_All)))) {
|
R_TRY(fs->OpenDirectory(dir, work_path, DirectoryOpenMode_All));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t parent_len = strnlen(work_path.str, sizeof(work_path.str) - 1);
|
const size_t parent_len = strnlen(work_path.str, sizeof(work_path.str) - 1);
|
||||||
|
|
||||||
@@ -38,9 +35,7 @@ class FsDirUtils {
|
|||||||
while (true) {
|
while (true) {
|
||||||
/* Read a single entry. */
|
/* Read a single entry. */
|
||||||
u64 read_count;
|
u64 read_count;
|
||||||
if (R_FAILED((rc = dir->Read(&read_count, ent_buf, 1)))) {
|
R_TRY(dir->Read(&read_count, ent_buf, 1));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we're out of entries, we're done. */
|
/* If we're out of entries, we're done. */
|
||||||
if (read_count == 0) {
|
if (read_count == 0) {
|
||||||
@@ -59,25 +54,17 @@ class FsDirUtils {
|
|||||||
strncat(work_path.str, ent_buf->name, sizeof(work_path.str) - 1 - parent_len);
|
strncat(work_path.str, ent_buf->name, sizeof(work_path.str) - 1 - parent_len);
|
||||||
if (is_dir) {
|
if (is_dir) {
|
||||||
/* Enter directory. */
|
/* Enter directory. */
|
||||||
if (R_FAILED((rc = on_enter_dir(work_path, ent_buf)))) {
|
R_TRY(on_enter_dir(work_path, ent_buf));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Append separator, recurse. */
|
/* Append separator, recurse. */
|
||||||
strncat(work_path.str, "/", sizeof(work_path.str) - 1 - parent_len - child_name_len);
|
strncat(work_path.str, "/", sizeof(work_path.str) - 1 - parent_len - child_name_len);
|
||||||
if (R_FAILED((rc = IterateDirectoryRecursivelyInternal(fs, work_path, ent_buf, on_enter_dir, on_exit_dir, on_file)))) {
|
R_TRY(IterateDirectoryRecursivelyInternal(fs, work_path, ent_buf, on_enter_dir, on_exit_dir, on_file));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Exit directory. */
|
/* Exit directory. */
|
||||||
if (R_FAILED((rc = on_exit_dir(work_path, ent_buf)))) {
|
R_TRY(on_exit_dir(work_path, ent_buf));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* Call file handler. */
|
/* Call file handler. */
|
||||||
if (R_FAILED((rc = on_file(work_path, ent_buf)))) {
|
R_TRY(on_file(work_path, ent_buf));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore parent path. */
|
/* Restore parent path. */
|
||||||
@@ -132,7 +119,7 @@ class FsDirUtils {
|
|||||||
static Result CopyDirectoryRecursively(IFileSystem *fs, const FsPath &dst_path, const FsPath &src_path, void *work_buf, size_t work_buf_size) {
|
static Result CopyDirectoryRecursively(IFileSystem *fs, const FsPath &dst_path, const FsPath &src_path, void *work_buf, size_t work_buf_size) {
|
||||||
return CopyDirectoryRecursively(fs, fs, dst_path, src_path, work_buf, work_buf_size);
|
return CopyDirectoryRecursively(fs, fs, dst_path, src_path, work_buf, work_buf_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure directory existence. */
|
/* Ensure directory existence. */
|
||||||
static Result EnsureDirectoryExists(IFileSystem *fs, const FsPath &path);
|
static Result EnsureDirectoryExists(IFileSystem *fs, const FsPath &path);
|
||||||
|
|
||||||
@@ -140,19 +127,16 @@ class FsDirUtils {
|
|||||||
template<typename F>
|
template<typename F>
|
||||||
static Result RetryUntilTargetNotLocked(F f) {
|
static Result RetryUntilTargetNotLocked(F f) {
|
||||||
const size_t MaxRetries = 10;
|
const size_t MaxRetries = 10;
|
||||||
Result rc = ResultSuccess;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < MaxRetries; i++) {
|
for (size_t i = 0; i < MaxRetries; i++) {
|
||||||
rc = f();
|
R_TRY_CATCH(f()) {
|
||||||
|
R_CATCH(ResultFsTargetLocked) {
|
||||||
if (rc != ResultFsTargetLocked) {
|
/* If target is locked, wait 100ms and try again. */
|
||||||
break;
|
svcSleepThread(100'000'000ul);
|
||||||
}
|
}
|
||||||
|
} R_END_TRY_CATCH;
|
||||||
/* If target is locked, wait 100ms and try again. */
|
|
||||||
svcSleepThread(100'000'000ul);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,11 +26,7 @@ static char *GetNormalizedDirectory(const char *dir_prefix) {
|
|||||||
/* Normalize the path. */
|
/* Normalize the path. */
|
||||||
char normal_path[FS_MAX_PATH + 1];
|
char normal_path[FS_MAX_PATH + 1];
|
||||||
size_t normal_path_len;
|
size_t normal_path_len;
|
||||||
Result rc = FsPathUtils::Normalize(normal_path, sizeof(normal_path), dir_prefix, &normal_path_len);
|
R_ASSERT(FsPathUtils::Normalize(normal_path, sizeof(normal_path), dir_prefix, &normal_path_len));
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
/* N calls svcBreak here. */
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure terminating '/' */
|
/* Ensure terminating '/' */
|
||||||
if (normal_path[normal_path_len-1] != '/') {
|
if (normal_path[normal_path_len-1] != '/') {
|
||||||
@@ -69,10 +65,7 @@ Result DirectoryRedirectionFileSystem::Initialize(const char *before, const char
|
|||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::GetFullPath(char *out, size_t out_size, const char *relative_path) {
|
Result DirectoryRedirectionFileSystem::GetFullPath(char *out, size_t out_size, const char *relative_path) {
|
||||||
FsPath tmp_rel_path;
|
FsPath tmp_rel_path;
|
||||||
Result rc = FsPathUtils::Normalize(tmp_rel_path.str, sizeof(tmp_rel_path), relative_path, nullptr);
|
R_TRY(FsPathUtils::Normalize(tmp_rel_path.str, sizeof(tmp_rel_path), relative_path, nullptr));
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (std::strncmp(tmp_rel_path.str, this->before_dir, this->before_dir_len) == 0) {
|
if (std::strncmp(tmp_rel_path.str, this->before_dir, this->before_dir_len) == 0) {
|
||||||
if (this->after_dir_len + strnlen(tmp_rel_path.str, FS_MAX_PATH) - this->before_dir_len > out_size) {
|
if (this->after_dir_len + strnlen(tmp_rel_path.str, FS_MAX_PATH) - this->before_dir_len > out_size) {
|
||||||
@@ -99,120 +92,64 @@ Result DirectoryRedirectionFileSystem::GetFullPath(char *out, size_t out_size, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::CreateFileImpl(const FsPath &path, uint64_t size, int flags) {
|
Result DirectoryRedirectionFileSystem::CreateFileImpl(const FsPath &path, uint64_t size, int flags) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->CreateFile(full_path, size, flags);
|
return this->base_fs->CreateFile(full_path, size, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::DeleteFileImpl(const FsPath &path) {
|
Result DirectoryRedirectionFileSystem::DeleteFileImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->DeleteFile(full_path);
|
return this->base_fs->DeleteFile(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::CreateDirectoryImpl(const FsPath &path) {
|
Result DirectoryRedirectionFileSystem::CreateDirectoryImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->CreateDirectory(full_path);
|
return this->base_fs->CreateDirectory(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::DeleteDirectoryImpl(const FsPath &path) {
|
Result DirectoryRedirectionFileSystem::DeleteDirectoryImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->DeleteDirectory(full_path);
|
return this->base_fs->DeleteDirectory(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::DeleteDirectoryRecursivelyImpl(const FsPath &path) {
|
Result DirectoryRedirectionFileSystem::DeleteDirectoryRecursivelyImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->DeleteDirectoryRecursively(full_path);
|
return this->base_fs->DeleteDirectoryRecursively(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::RenameFileImpl(const FsPath &old_path, const FsPath &new_path) {
|
Result DirectoryRedirectionFileSystem::RenameFileImpl(const FsPath &old_path, const FsPath &new_path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_old_path, full_new_path;
|
FsPath full_old_path, full_new_path;
|
||||||
|
R_TRY(GetFullPath(full_old_path, old_path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_old_path, old_path)))) {
|
R_TRY(GetFullPath(full_new_path, new_path));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED((rc = GetFullPath(full_new_path, new_path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->RenameFile(full_old_path, full_new_path);
|
return this->base_fs->RenameFile(full_old_path, full_new_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) {
|
Result DirectoryRedirectionFileSystem::RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_old_path, full_new_path;
|
FsPath full_old_path, full_new_path;
|
||||||
|
R_TRY(GetFullPath(full_old_path, old_path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_old_path, old_path)))) {
|
R_TRY(GetFullPath(full_new_path, new_path));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED((rc = GetFullPath(full_new_path, new_path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->RenameDirectory(full_old_path, full_new_path);
|
return this->base_fs->RenameDirectory(full_old_path, full_new_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) {
|
Result DirectoryRedirectionFileSystem::GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->GetEntryType(out, full_path);
|
return this->base_fs->GetEntryType(out, full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::OpenFileImpl(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) {
|
Result DirectoryRedirectionFileSystem::OpenFileImpl(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->OpenFile(out_file, full_path, mode);
|
return this->base_fs->OpenFile(out_file, full_path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, const FsPath &path, DirectoryOpenMode mode) {
|
Result DirectoryRedirectionFileSystem::OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, const FsPath &path, DirectoryOpenMode mode) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->OpenDirectory(out_dir, full_path, mode);
|
return this->base_fs->OpenDirectory(out_dir, full_path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,56 +158,31 @@ Result DirectoryRedirectionFileSystem::CommitImpl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) {
|
Result DirectoryRedirectionFileSystem::GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->GetFreeSpaceSize(out, full_path);
|
return this->base_fs->GetFreeSpaceSize(out, full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) {
|
Result DirectoryRedirectionFileSystem::GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->GetTotalSpaceSize(out, full_path);
|
return this->base_fs->GetTotalSpaceSize(out, full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::CleanDirectoryRecursivelyImpl(const FsPath &path) {
|
Result DirectoryRedirectionFileSystem::CleanDirectoryRecursivelyImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->CleanDirectoryRecursively(full_path);
|
return this->base_fs->CleanDirectoryRecursively(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::GetFileTimeStampRawImpl(FsTimeStampRaw *out, const FsPath &path) {
|
Result DirectoryRedirectionFileSystem::GetFileTimeStampRawImpl(FsTimeStampRaw *out, const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->GetFileTimeStampRaw(out, full_path);
|
return this->base_fs->GetFileTimeStampRaw(out, full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectoryRedirectionFileSystem::QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, const FsPath &path) {
|
Result DirectoryRedirectionFileSystem::QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->QueryEntry(out, out_size, in, in_size, query, full_path);
|
return this->base_fs->QueryEntry(out, out_size, in, in_size, query, full_path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,17 +31,11 @@ class DirectoryRedirectionFileSystem : public IFileSystem {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
DirectoryRedirectionFileSystem(IFileSystem *fs, const char *before, const char *after) : base_fs(fs) {
|
DirectoryRedirectionFileSystem(IFileSystem *fs, const char *before, const char *after) : base_fs(fs) {
|
||||||
Result rc = this->Initialize(before, after);
|
R_ASSERT(this->Initialize(before, after));
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectoryRedirectionFileSystem(std::shared_ptr<IFileSystem> fs, const char *before, const char *after) : base_fs(fs) {
|
DirectoryRedirectionFileSystem(std::shared_ptr<IFileSystem> fs, const char *before, const char *after) : base_fs(fs) {
|
||||||
Result rc = this->Initialize(before, after);
|
R_ASSERT(this->Initialize(before, after));
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -62,59 +62,44 @@ class DirectorySaveDataFile : public IFile {
|
|||||||
/* ================================================================================================ */
|
/* ================================================================================================ */
|
||||||
|
|
||||||
Result DirectorySaveDataFileSystem::Initialize() {
|
Result DirectorySaveDataFileSystem::Initialize() {
|
||||||
Result rc;
|
|
||||||
DirectoryEntryType ent_type;
|
DirectoryEntryType ent_type;
|
||||||
|
|
||||||
/* Check that the working directory exists. */
|
/* Check that the working directory exists. */
|
||||||
if (R_FAILED((rc = this->fs->GetEntryType(&ent_type, WorkingDirectoryPath)))) {
|
R_TRY_CATCH(this->fs->GetEntryType(&ent_type, WorkingDirectoryPath)) {
|
||||||
/* If path isn't found, create working directory and committed directory. */
|
/* If path isn't found, create working directory and committed directory. */
|
||||||
if (rc == ResultFsPathNotFound) {
|
R_CATCH(ResultFsPathNotFound) {
|
||||||
if (R_FAILED((rc = this->fs->CreateDirectory(WorkingDirectoryPath)))) {
|
R_TRY(this->fs->CreateDirectory(WorkingDirectoryPath));
|
||||||
return rc;
|
R_TRY(this->fs->CreateDirectory(CommittedDirectoryPath));
|
||||||
}
|
|
||||||
if (R_FAILED((rc = this->fs->CreateDirectory(CommittedDirectoryPath)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
}
|
} R_END_TRY_CATCH;
|
||||||
|
|
||||||
/* Now check for the committed directory. */
|
/* Now check for the committed directory. */
|
||||||
rc = this->fs->GetEntryType(&ent_type, CommittedDirectoryPath);
|
R_TRY_CATCH(this->fs->GetEntryType(&ent_type, CommittedDirectoryPath)) {
|
||||||
if (R_SUCCEEDED(rc)) {
|
/* Committed doesn't exist, so synchronize and rename. */
|
||||||
/* If committed exists, synchronize it to the working directory. */
|
R_CATCH(ResultFsPathNotFound) {
|
||||||
return this->SynchronizeDirectory(WorkingDirectoryPath, CommittedDirectoryPath);
|
R_TRY(this->SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath));
|
||||||
} else if (rc == ResultFsPathNotFound) {
|
return this->fs->RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath);
|
||||||
if (R_FAILED((rc = this->SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
return this->fs->RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath);
|
} R_END_TRY_CATCH;
|
||||||
} else {
|
|
||||||
return rc;
|
/* If committed exists, synchronize it to the working directory. */
|
||||||
}
|
return this->SynchronizeDirectory(WorkingDirectoryPath, CommittedDirectoryPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectorySaveDataFileSystem::SynchronizeDirectory(const FsPath &dst_dir, const FsPath &src_dir) {
|
Result DirectorySaveDataFileSystem::SynchronizeDirectory(const FsPath &dst_dir, const FsPath &src_dir) {
|
||||||
Result rc;
|
|
||||||
|
|
||||||
/* Delete destination dir and recreate it. */
|
/* Delete destination dir and recreate it. */
|
||||||
if (R_FAILED((rc = this->fs->DeleteDirectoryRecursively(dst_dir)))) {
|
R_TRY_CATCH(this->fs->DeleteDirectoryRecursively(dst_dir)) {
|
||||||
/* Nintendo returns error unconditionally, but I think that's a bug in their code. */
|
R_CATCH(ResultFsPathNotFound) {
|
||||||
if (rc != ResultFsPathNotFound) {
|
/* Nintendo returns error unconditionally, but I think that's a bug in their code. */
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
}
|
} R_END_TRY_CATCH;
|
||||||
if (R_FAILED((rc = this->fs->CreateDirectory(dst_dir)))) {
|
|
||||||
return rc;
|
R_TRY(this->fs->CreateDirectory(dst_dir));
|
||||||
}
|
|
||||||
|
|
||||||
/* Get a buffer to work with. */
|
/* Get a buffer to work with. */
|
||||||
void *work_buf = nullptr;
|
void *work_buf = nullptr;
|
||||||
size_t work_buf_size = 0;
|
size_t work_buf_size = 0;
|
||||||
if (R_FAILED((rc = this->AllocateWorkBuffer(&work_buf, &work_buf_size, IdealWorkBuffersize)))) {
|
R_TRY(this->AllocateWorkBuffer(&work_buf, &work_buf_size, IdealWorkBuffersize));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
ON_SCOPE_EXIT { free(work_buf); };
|
ON_SCOPE_EXIT { free(work_buf); };
|
||||||
|
|
||||||
return FsDirUtils::CopyDirectoryRecursively(this->fs, dst_dir, src_dir, work_buf, work_buf_size);
|
return FsDirUtils::CopyDirectoryRecursively(this->fs, dst_dir, src_dir, work_buf, work_buf_size);
|
||||||
@@ -149,11 +134,11 @@ Result DirectorySaveDataFileSystem::GetFullPath(char *out, size_t out_size, cons
|
|||||||
if (relative_path[0] != '/') {
|
if (relative_path[0] != '/') {
|
||||||
return ResultFsInvalidPath;
|
return ResultFsInvalidPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy working directory path. */
|
/* Copy working directory path. */
|
||||||
std::strncpy(out, WorkingDirectoryPath.str, out_size);
|
std::strncpy(out, WorkingDirectoryPath.str, out_size);
|
||||||
out[out_size-1] = 0;
|
out[out_size-1] = 0;
|
||||||
|
|
||||||
/* Normalize it. */
|
/* Normalize it. */
|
||||||
constexpr size_t working_len = WorkingDirectoryPathLen - 1;
|
constexpr size_t working_len = WorkingDirectoryPathLen - 1;
|
||||||
return FsPathUtils::Normalize(out + working_len, out_size - working_len, relative_path, nullptr);
|
return FsPathUtils::Normalize(out + working_len, out_size - working_len, relative_path, nullptr);
|
||||||
@@ -168,20 +153,13 @@ void DirectorySaveDataFileSystem::OnWritableFileClose() {
|
|||||||
|
|
||||||
Result DirectorySaveDataFileSystem::CopySaveFromProxy() {
|
Result DirectorySaveDataFileSystem::CopySaveFromProxy() {
|
||||||
if (this->proxy_save_fs != nullptr) {
|
if (this->proxy_save_fs != nullptr) {
|
||||||
Result rc;
|
|
||||||
|
|
||||||
/* Get a buffer to work with. */
|
/* Get a buffer to work with. */
|
||||||
void *work_buf = nullptr;
|
void *work_buf = nullptr;
|
||||||
size_t work_buf_size = 0;
|
size_t work_buf_size = 0;
|
||||||
if (R_FAILED((rc = this->AllocateWorkBuffer(&work_buf, &work_buf_size, IdealWorkBuffersize)))) {
|
R_TRY(this->AllocateWorkBuffer(&work_buf, &work_buf_size, IdealWorkBuffersize));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
ON_SCOPE_EXIT { free(work_buf); };
|
ON_SCOPE_EXIT { free(work_buf); };
|
||||||
|
|
||||||
rc = FsDirUtils::CopyDirectoryRecursively(this, this->proxy_save_fs.get(), FsPathUtils::RootPath, FsPathUtils::RootPath, work_buf, work_buf_size);
|
R_TRY(FsDirUtils::CopyDirectoryRecursively(this, this->proxy_save_fs.get(), FsPathUtils::RootPath, FsPathUtils::RootPath, work_buf, work_buf_size));
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
return this->Commit();
|
return this->Commit();
|
||||||
}
|
}
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
@@ -190,125 +168,81 @@ Result DirectorySaveDataFileSystem::CopySaveFromProxy() {
|
|||||||
/* ================================================================================================ */
|
/* ================================================================================================ */
|
||||||
|
|
||||||
Result DirectorySaveDataFileSystem::CreateFileImpl(const FsPath &path, uint64_t size, int flags) {
|
Result DirectorySaveDataFileSystem::CreateFileImpl(const FsPath &path, uint64_t size, int flags) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::scoped_lock<HosMutex> lk(this->lock);
|
std::scoped_lock<HosMutex> lk(this->lock);
|
||||||
return this->fs->CreateFile(full_path, size, flags);
|
return this->fs->CreateFile(full_path, size, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectorySaveDataFileSystem::DeleteFileImpl(const FsPath &path) {
|
Result DirectorySaveDataFileSystem::DeleteFileImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::scoped_lock<HosMutex> lk(this->lock);
|
std::scoped_lock<HosMutex> lk(this->lock);
|
||||||
return this->fs->DeleteFile(full_path);
|
return this->fs->DeleteFile(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectorySaveDataFileSystem::CreateDirectoryImpl(const FsPath &path) {
|
Result DirectorySaveDataFileSystem::CreateDirectoryImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::scoped_lock<HosMutex> lk(this->lock);
|
std::scoped_lock<HosMutex> lk(this->lock);
|
||||||
return this->fs->CreateDirectory(full_path);
|
return this->fs->CreateDirectory(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectorySaveDataFileSystem::DeleteDirectoryImpl(const FsPath &path) {
|
Result DirectorySaveDataFileSystem::DeleteDirectoryImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::scoped_lock<HosMutex> lk(this->lock);
|
std::scoped_lock<HosMutex> lk(this->lock);
|
||||||
return this->fs->DeleteDirectory(full_path);
|
return this->fs->DeleteDirectory(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectorySaveDataFileSystem::DeleteDirectoryRecursivelyImpl(const FsPath &path) {
|
Result DirectorySaveDataFileSystem::DeleteDirectoryRecursivelyImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::scoped_lock<HosMutex> lk(this->lock);
|
std::scoped_lock<HosMutex> lk(this->lock);
|
||||||
return this->fs->DeleteDirectoryRecursively(full_path);
|
return this->fs->DeleteDirectoryRecursively(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectorySaveDataFileSystem::RenameFileImpl(const FsPath &old_path, const FsPath &new_path) {
|
Result DirectorySaveDataFileSystem::RenameFileImpl(const FsPath &old_path, const FsPath &new_path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_old_path, full_new_path;
|
FsPath full_old_path, full_new_path;
|
||||||
|
R_TRY(GetFullPath(full_old_path, old_path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_old_path, old_path)))) {
|
R_TRY(GetFullPath(full_new_path, new_path));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED((rc = GetFullPath(full_new_path, new_path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::scoped_lock<HosMutex> lk(this->lock);
|
std::scoped_lock<HosMutex> lk(this->lock);
|
||||||
return this->fs->RenameFile(full_old_path, full_new_path);
|
return this->fs->RenameFile(full_old_path, full_new_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectorySaveDataFileSystem::RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) {
|
Result DirectorySaveDataFileSystem::RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_old_path, full_new_path;
|
FsPath full_old_path, full_new_path;
|
||||||
|
R_TRY(GetFullPath(full_old_path, old_path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_old_path, old_path)))) {
|
R_TRY(GetFullPath(full_new_path, new_path));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED((rc = GetFullPath(full_new_path, new_path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::scoped_lock<HosMutex> lk(this->lock);
|
std::scoped_lock<HosMutex> lk(this->lock);
|
||||||
return this->fs->RenameDirectory(full_old_path, full_new_path);
|
return this->fs->RenameDirectory(full_old_path, full_new_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectorySaveDataFileSystem::GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) {
|
Result DirectorySaveDataFileSystem::GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::scoped_lock<HosMutex> lk(this->lock);
|
std::scoped_lock<HosMutex> lk(this->lock);
|
||||||
return this->fs->GetEntryType(out, full_path);
|
return this->fs->GetEntryType(out, full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectorySaveDataFileSystem::OpenFileImpl(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) {
|
Result DirectorySaveDataFileSystem::OpenFileImpl(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::scoped_lock<HosMutex> lk(this->lock);
|
std::scoped_lock<HosMutex> lk(this->lock);
|
||||||
|
|
||||||
{
|
{
|
||||||
/* Open the raw file. */
|
/* Open the raw file. */
|
||||||
std::unique_ptr<IFile> file;
|
std::unique_ptr<IFile> file;
|
||||||
if (R_FAILED((rc = this->fs->OpenFile(file, full_path, mode)))) {
|
R_TRY(this->fs->OpenFile(file, full_path, mode));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create DirectorySaveDataFile wrapper. */
|
/* Create DirectorySaveDataFile wrapper. */
|
||||||
out_file = std::make_unique<DirectorySaveDataFile>(std::move(file), this, mode);
|
out_file = std::make_unique<DirectorySaveDataFile>(std::move(file), this, mode);
|
||||||
@@ -328,13 +262,9 @@ Result DirectorySaveDataFileSystem::OpenFileImpl(std::unique_ptr<IFile> &out_fil
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result DirectorySaveDataFileSystem::OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, const FsPath &path, DirectoryOpenMode mode) {
|
Result DirectorySaveDataFileSystem::OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, const FsPath &path, DirectoryOpenMode mode) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::scoped_lock<HosMutex> lk(this->lock);
|
std::scoped_lock<HosMutex> lk(this->lock);
|
||||||
return this->fs->OpenDirectory(out_dir, full_path, mode);
|
return this->fs->OpenDirectory(out_dir, full_path, mode);
|
||||||
}
|
}
|
||||||
@@ -349,7 +279,6 @@ Result DirectorySaveDataFileSystem::CommitImpl() {
|
|||||||
/* Instead, we will synchronize first, then delete committed, then rename. */
|
/* Instead, we will synchronize first, then delete committed, then rename. */
|
||||||
|
|
||||||
std::scoped_lock<HosMutex> lk(this->lock);
|
std::scoped_lock<HosMutex> lk(this->lock);
|
||||||
Result rc;
|
|
||||||
|
|
||||||
/* Ensure we don't have any open writable files. */
|
/* Ensure we don't have any open writable files. */
|
||||||
if (this->open_writable_files != 0) {
|
if (this->open_writable_files != 0) {
|
||||||
@@ -361,25 +290,20 @@ Result DirectorySaveDataFileSystem::CommitImpl() {
|
|||||||
const auto RenameSynchDir = [&]() { return this->fs->RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath); };
|
const auto RenameSynchDir = [&]() { return this->fs->RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath); };
|
||||||
|
|
||||||
/* Synchronize working directory. */
|
/* Synchronize working directory. */
|
||||||
if (R_FAILED((rc = FsDirUtils::RetryUntilTargetNotLocked(std::move(SynchronizeWorkingDir))))) {
|
R_TRY(FsDirUtils::RetryUntilTargetNotLocked(std::move(SynchronizeWorkingDir)));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Delete committed directory. */
|
/* Delete committed directory. */
|
||||||
if (R_FAILED((rc = FsDirUtils::RetryUntilTargetNotLocked(std::move(DeleteCommittedDir))))) {
|
R_TRY_CATCH(FsDirUtils::RetryUntilTargetNotLocked(std::move(DeleteCommittedDir))) {
|
||||||
/* It is okay for us to not have a committed directory here. */
|
R_CATCH(ResultFsPathNotFound) {
|
||||||
if (rc != ResultFsPathNotFound) {
|
/* It is okay for us to not have a committed directory here. */
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
}
|
} R_END_TRY_CATCH;
|
||||||
|
|
||||||
/* Rename synchronizing directory to committed directory. */
|
/* Rename synchronizing directory to committed directory. */
|
||||||
if (R_FAILED((rc = FsDirUtils::RetryUntilTargetNotLocked(std::move(RenameSynchDir))))) {
|
R_TRY(FsDirUtils::RetryUntilTargetNotLocked(std::move(RenameSynchDir)));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: Should I call this->fs->Commit()? Nintendo does not. */
|
/* TODO: Should I call this->fs->Commit()? Nintendo does not. */
|
||||||
return rc;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result DirectorySaveDataFileSystem::GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) {
|
Result DirectorySaveDataFileSystem::GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) {
|
||||||
@@ -393,13 +317,9 @@ Result DirectorySaveDataFileSystem::GetTotalSpaceSizeImpl(uint64_t *out, const F
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result DirectorySaveDataFileSystem::CleanDirectoryRecursivelyImpl(const FsPath &path) {
|
Result DirectorySaveDataFileSystem::CleanDirectoryRecursivelyImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::scoped_lock<HosMutex> lk(this->lock);
|
std::scoped_lock<HosMutex> lk(this->lock);
|
||||||
return this->fs->CleanDirectoryRecursively(full_path);
|
return this->fs->CleanDirectoryRecursively(full_path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,26 +43,17 @@ class DirectorySaveDataFileSystem : public IFileSystem {
|
|||||||
public:
|
public:
|
||||||
DirectorySaveDataFileSystem(IFileSystem *fs, std::unique_ptr<IFileSystem> pfs) : unique_fs(fs), proxy_save_fs(std::move(pfs)) {
|
DirectorySaveDataFileSystem(IFileSystem *fs, std::unique_ptr<IFileSystem> pfs) : unique_fs(fs), proxy_save_fs(std::move(pfs)) {
|
||||||
this->fs = this->unique_fs.get();
|
this->fs = this->unique_fs.get();
|
||||||
Result rc = this->Initialize();
|
R_ASSERT(this->Initialize());
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectorySaveDataFileSystem(std::unique_ptr<IFileSystem> fs, std::unique_ptr<IFileSystem> pfs) : unique_fs(std::move(fs)), proxy_save_fs(std::move(pfs)) {
|
DirectorySaveDataFileSystem(std::unique_ptr<IFileSystem> fs, std::unique_ptr<IFileSystem> pfs) : unique_fs(std::move(fs)), proxy_save_fs(std::move(pfs)) {
|
||||||
this->fs = this->unique_fs.get();
|
this->fs = this->unique_fs.get();
|
||||||
Result rc = this->Initialize();
|
R_ASSERT(this->Initialize());
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectorySaveDataFileSystem(std::shared_ptr<IFileSystem> fs, std::unique_ptr<IFileSystem> pfs) : shared_fs(fs), proxy_save_fs(std::move(pfs)) {
|
DirectorySaveDataFileSystem(std::shared_ptr<IFileSystem> fs, std::unique_ptr<IFileSystem> pfs) : shared_fs(fs), proxy_save_fs(std::move(pfs)) {
|
||||||
this->fs = this->shared_fs.get();
|
this->fs = this->shared_fs.get();
|
||||||
Result rc = this->Initialize();
|
R_ASSERT(this->Initialize());
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~DirectorySaveDataFileSystem() { }
|
virtual ~DirectorySaveDataFileSystem() { }
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ Result FileStorage::UpdateSize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result FileStorage::Read(void *buffer, size_t size, u64 offset) {
|
Result FileStorage::Read(void *buffer, size_t size, u64 offset) {
|
||||||
Result rc;
|
|
||||||
u64 read_size;
|
u64 read_size;
|
||||||
|
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
@@ -38,9 +37,7 @@ Result FileStorage::Read(void *buffer, size_t size, u64 offset) {
|
|||||||
if (buffer == nullptr) {
|
if (buffer == nullptr) {
|
||||||
return ResultFsNullptrArgument;
|
return ResultFsNullptrArgument;
|
||||||
}
|
}
|
||||||
if (R_FAILED((rc = this->UpdateSize()))) {
|
R_TRY(this->UpdateSize());
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if (!IStorage::IsRangeValid(offset, size, this->size)) {
|
if (!IStorage::IsRangeValid(offset, size, this->size)) {
|
||||||
return ResultFsOutOfRange;
|
return ResultFsOutOfRange;
|
||||||
}
|
}
|
||||||
@@ -54,17 +51,13 @@ Result FileStorage::Read(void *buffer, size_t size, u64 offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result FileStorage::Write(void *buffer, size_t size, u64 offset) {
|
Result FileStorage::Write(void *buffer, size_t size, u64 offset) {
|
||||||
Result rc;
|
|
||||||
|
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
if (buffer == nullptr) {
|
if (buffer == nullptr) {
|
||||||
return ResultFsNullptrArgument;
|
return ResultFsNullptrArgument;
|
||||||
}
|
}
|
||||||
if (R_FAILED((rc = this->UpdateSize()))) {
|
R_TRY(this->UpdateSize());
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if (!IStorage::IsRangeValid(offset, size, this->size)) {
|
if (!IStorage::IsRangeValid(offset, size, this->size)) {
|
||||||
return ResultFsOutOfRange;
|
return ResultFsOutOfRange;
|
||||||
}
|
}
|
||||||
@@ -77,10 +70,7 @@ Result FileStorage::Flush() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result FileStorage::GetSize(u64 *out_size) {
|
Result FileStorage::GetSize(u64 *out_size) {
|
||||||
Result rc = this->UpdateSize();
|
R_TRY(this->UpdateSize());
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
*out_size = this->size;
|
*out_size = this->size;
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
@@ -91,8 +81,6 @@ Result FileStorage::SetSize(u64 size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result FileStorage::OperateRange(FsOperationId operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) {
|
Result FileStorage::OperateRange(FsOperationId operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) {
|
||||||
Result rc;
|
|
||||||
|
|
||||||
switch (operation_type) {
|
switch (operation_type) {
|
||||||
case FsOperationId_InvalidateCache:
|
case FsOperationId_InvalidateCache:
|
||||||
case FsOperationId_QueryRange:
|
case FsOperationId_QueryRange:
|
||||||
@@ -106,9 +94,7 @@ Result FileStorage::OperateRange(FsOperationId operation_type, u64 offset, u64 s
|
|||||||
}
|
}
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
if (R_FAILED((rc = this->UpdateSize()))) {
|
R_TRY(this->UpdateSize());
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
/* N checks for positivity + signed overflow on offset/size here, but we're using unsigned types... */
|
/* N checks for positivity + signed overflow on offset/size here, but we're using unsigned types... */
|
||||||
return this->file->OperateRange(operation_type, offset, size, out_range_info);
|
return this->file->OperateRange(operation_type, offset, size, out_range_info);
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|||||||
@@ -15,12 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
enum OpenMode {
|
enum OpenMode {
|
||||||
OpenMode_Read = (1 << 0),
|
OpenMode_Read = (1 << 0),
|
||||||
OpenMode_Write = (1 << 1),
|
OpenMode_Write = (1 << 1),
|
||||||
OpenMode_Append = (1 << 2),
|
OpenMode_Append = (1 << 2),
|
||||||
|
|
||||||
OpenMode_ReadWrite = OpenMode_Read | OpenMode_Write,
|
OpenMode_ReadWrite = OpenMode_Read | OpenMode_Write,
|
||||||
OpenMode_All = OpenMode_ReadWrite | OpenMode_Append,
|
OpenMode_All = OpenMode_ReadWrite | OpenMode_Append,
|
||||||
};
|
};
|
||||||
@@ -28,7 +28,7 @@ enum OpenMode {
|
|||||||
enum DirectoryOpenMode {
|
enum DirectoryOpenMode {
|
||||||
DirectoryOpenMode_Directories = (1 << 0),
|
DirectoryOpenMode_Directories = (1 << 0),
|
||||||
DirectoryOpenMode_Files = (1 << 1),
|
DirectoryOpenMode_Files = (1 << 1),
|
||||||
|
|
||||||
DirectoryOpenMode_All = (DirectoryOpenMode_Directories | DirectoryOpenMode_Files),
|
DirectoryOpenMode_All = (DirectoryOpenMode_Directories | DirectoryOpenMode_Files),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,6 @@
|
|||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
enum FsIDirectoryCmd : u32 {
|
|
||||||
FsIDirectoryCmd_Read = 0,
|
|
||||||
FsIDirectoryCmd_GetEntryCount = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
class IDirectory {
|
class IDirectory {
|
||||||
public:
|
public:
|
||||||
virtual ~IDirectory() {}
|
virtual ~IDirectory() {}
|
||||||
@@ -56,6 +51,11 @@ class IDirectory {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class IDirectoryInterface : public IServiceObject {
|
class IDirectoryInterface : public IServiceObject {
|
||||||
|
private:
|
||||||
|
enum class CommandId {
|
||||||
|
Read = 0,
|
||||||
|
GetEntryCount = 1,
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<IDirectory> base_dir;
|
std::unique_ptr<IDirectory> base_dir;
|
||||||
public:
|
public:
|
||||||
@@ -77,8 +77,8 @@ class IDirectoryInterface : public IServiceObject {
|
|||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
/* 1.0.0- */
|
/* 1.0.0- */
|
||||||
MakeServiceCommandMeta<FsIDirectoryCmd_Read, &IDirectoryInterface::Read>(),
|
MAKE_SERVICE_COMMAND_META(IDirectoryInterface, Read),
|
||||||
MakeServiceCommandMeta<FsIDirectoryCmd_GetEntryCount, &IDirectoryInterface::GetEntryCount>(),
|
MAKE_SERVICE_COMMAND_META(IDirectoryInterface, GetEntryCount),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -104,13 +104,10 @@ class ProxyDirectory : public IDirectory {
|
|||||||
public:
|
public:
|
||||||
virtual Result ReadImpl(uint64_t *out_count, FsDirectoryEntry *out_entries, uint64_t max_entries) {
|
virtual Result ReadImpl(uint64_t *out_count, FsDirectoryEntry *out_entries, uint64_t max_entries) {
|
||||||
size_t count;
|
size_t count;
|
||||||
|
R_TRY(fsDirRead(this->base_dir.get(), 0, &count, max_entries, out_entries));
|
||||||
|
|
||||||
Result rc = fsDirRead(this->base_dir.get(), 0, &count, max_entries, out_entries);
|
*out_count = count;
|
||||||
if (R_SUCCEEDED(rc)) {
|
return ResultSuccess;
|
||||||
*out_count = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
virtual Result GetEntryCountImpl(uint64_t *count) {
|
virtual Result GetEntryCountImpl(uint64_t *count) {
|
||||||
return fsDirGetEntryCount(this->base_dir.get(), count);
|
return fsDirGetEntryCount(this->base_dir.get(), count);
|
||||||
|
|||||||
@@ -20,15 +20,6 @@
|
|||||||
|
|
||||||
#include "fs_shim.h"
|
#include "fs_shim.h"
|
||||||
|
|
||||||
enum FsIFileCmd : u32 {
|
|
||||||
FsIFileCmd_Read = 0,
|
|
||||||
FsIFileCmd_Write = 1,
|
|
||||||
FsIFileCmd_Flush = 2,
|
|
||||||
FsIFileCmd_SetSize = 3,
|
|
||||||
FsIFileCmd_GetSize = 4,
|
|
||||||
FsIFileCmd_OperateRange = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
class IFile {
|
class IFile {
|
||||||
public:
|
public:
|
||||||
virtual ~IFile() {}
|
virtual ~IFile() {}
|
||||||
@@ -106,6 +97,15 @@ class IFile {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class IFileInterface : public IServiceObject {
|
class IFileInterface : public IServiceObject {
|
||||||
|
private:
|
||||||
|
enum class CommandId {
|
||||||
|
Read = 0,
|
||||||
|
Write = 1,
|
||||||
|
Flush = 2,
|
||||||
|
SetSize = 3,
|
||||||
|
GetSize = 4,
|
||||||
|
OperateRange = 5,
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<IFile> base_file;
|
std::unique_ptr<IFile> base_file;
|
||||||
public:
|
public:
|
||||||
@@ -139,14 +139,14 @@ class IFileInterface : public IServiceObject {
|
|||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
/* 1.0.0- */
|
/* 1.0.0- */
|
||||||
MakeServiceCommandMeta<FsIFileCmd_Read, &IFileInterface::Read>(),
|
MAKE_SERVICE_COMMAND_META(IFileInterface, Read),
|
||||||
MakeServiceCommandMeta<FsIFileCmd_Write, &IFileInterface::Write>(),
|
MAKE_SERVICE_COMMAND_META(IFileInterface, Write),
|
||||||
MakeServiceCommandMeta<FsIFileCmd_Flush, &IFileInterface::Flush>(),
|
MAKE_SERVICE_COMMAND_META(IFileInterface, Flush),
|
||||||
MakeServiceCommandMeta<FsIFileCmd_SetSize, &IFileInterface::SetSize>(),
|
MAKE_SERVICE_COMMAND_META(IFileInterface, SetSize),
|
||||||
MakeServiceCommandMeta<FsIFileCmd_GetSize, &IFileInterface::GetSize>(),
|
MAKE_SERVICE_COMMAND_META(IFileInterface, GetSize),
|
||||||
|
|
||||||
/* 4.0.0- */
|
/* 4.0.0- */
|
||||||
MakeServiceCommandMeta<FsIFileCmd_OperateRange, &IFileInterface::OperateRange, FirmwareVersion_400>(),
|
MAKE_SERVICE_COMMAND_META(IFileInterface, OperateRange, FirmwareVersion_400),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -172,13 +172,10 @@ class ProxyFile : public IFile {
|
|||||||
public:
|
public:
|
||||||
virtual Result ReadImpl(u64 *out, u64 offset, void *buffer, u64 size) override {
|
virtual Result ReadImpl(u64 *out, u64 offset, void *buffer, u64 size) override {
|
||||||
size_t out_sz;
|
size_t out_sz;
|
||||||
|
R_TRY(fsFileRead(this->base_file.get(), offset, buffer, size, FS_READOPTION_NONE, &out_sz));
|
||||||
|
|
||||||
Result rc = fsFileRead(this->base_file.get(), offset, buffer, size, FS_READOPTION_NONE, &out_sz);
|
*out = out_sz;
|
||||||
if (R_SUCCEEDED(rc)) {
|
return ResultSuccess;
|
||||||
*out = out_sz;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
virtual Result GetSizeImpl(u64 *out) override {
|
virtual Result GetSizeImpl(u64 *out) override {
|
||||||
return fsFileGetSize(this->base_file.get(), out);
|
return fsFileGetSize(this->base_file.get(), out);
|
||||||
|
|||||||
@@ -26,30 +26,6 @@
|
|||||||
#include "fs_ifile.hpp"
|
#include "fs_ifile.hpp"
|
||||||
#include "fs_idirectory.hpp"
|
#include "fs_idirectory.hpp"
|
||||||
|
|
||||||
enum FsIFileSystemCmd : u32 {
|
|
||||||
/* 1.0.0+ */
|
|
||||||
FsIFileSystemCmd_CreateFile = 0,
|
|
||||||
FsIFileSystemCmd_DeleteFile = 1,
|
|
||||||
FsIFileSystemCmd_CreateDirectory = 2,
|
|
||||||
FsIFileSystemCmd_DeleteDirectory = 3,
|
|
||||||
FsIFileSystemCmd_DeleteDirectoryRecursively = 4,
|
|
||||||
FsIFileSystemCmd_RenameFile = 5,
|
|
||||||
FsIFileSystemCmd_RenameDirectory = 6,
|
|
||||||
FsIFileSystemCmd_GetEntryType = 7,
|
|
||||||
FsIFileSystemCmd_OpenFile = 8,
|
|
||||||
FsIFileSystemCmd_OpenDirectory = 9,
|
|
||||||
FsIFileSystemCmd_Commit = 10,
|
|
||||||
FsIFileSystemCmd_GetFreeSpaceSize = 11,
|
|
||||||
FsIFileSystemCmd_GetTotalSpaceSize = 12,
|
|
||||||
|
|
||||||
/* 3.0.0+ */
|
|
||||||
FsIFileSystemCmd_CleanDirectoryRecursively = 13,
|
|
||||||
FsIFileSystemCmd_GetFileTimeStampRaw = 14,
|
|
||||||
|
|
||||||
/* 4.0.0+ */
|
|
||||||
FsIFileSystemCmd_QueryEntry = 15,
|
|
||||||
};
|
|
||||||
|
|
||||||
class IFile;
|
class IFile;
|
||||||
class IDirectory;
|
class IDirectory;
|
||||||
|
|
||||||
@@ -197,6 +173,30 @@ class IFileSystem {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class IFileSystemInterface : public IServiceObject {
|
class IFileSystemInterface : public IServiceObject {
|
||||||
|
private:
|
||||||
|
enum class CommandId {
|
||||||
|
/* 1.0.0+ */
|
||||||
|
CreateFile = 0,
|
||||||
|
DeleteFile = 1,
|
||||||
|
CreateDirectory = 2,
|
||||||
|
DeleteDirectory = 3,
|
||||||
|
DeleteDirectoryRecursively = 4,
|
||||||
|
RenameFile = 5,
|
||||||
|
RenameDirectory = 6,
|
||||||
|
GetEntryType = 7,
|
||||||
|
OpenFile = 8,
|
||||||
|
OpenDirectory = 9,
|
||||||
|
Commit = 10,
|
||||||
|
GetFreeSpaceSize = 11,
|
||||||
|
GetTotalSpaceSize = 12,
|
||||||
|
|
||||||
|
/* 3.0.0+ */
|
||||||
|
CleanDirectoryRecursively = 13,
|
||||||
|
GetFileTimeStampRaw = 14,
|
||||||
|
|
||||||
|
/* 4.0.0+ */
|
||||||
|
QueryEntry = 15,
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<IFileSystem> unique_fs;
|
std::unique_ptr<IFileSystem> unique_fs;
|
||||||
std::shared_ptr<IFileSystem> shared_fs;
|
std::shared_ptr<IFileSystem> shared_fs;
|
||||||
@@ -216,55 +216,35 @@ class IFileSystemInterface : public IServiceObject {
|
|||||||
/* Actual command API. */
|
/* Actual command API. */
|
||||||
virtual Result CreateFile(InPointer<char> in_path, uint64_t size, int flags) final {
|
virtual Result CreateFile(InPointer<char> in_path, uint64_t size, int flags) final {
|
||||||
FsPath path;
|
FsPath path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer));
|
||||||
Result rc;
|
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->CreateFile(path, size, flags);
|
return this->base_fs->CreateFile(path, size, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result DeleteFile(InPointer<char> in_path) final {
|
virtual Result DeleteFile(InPointer<char> in_path) final {
|
||||||
FsPath path;
|
FsPath path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer));
|
||||||
Result rc;
|
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->DeleteFile(path);
|
return this->base_fs->DeleteFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result CreateDirectory(InPointer<char> in_path) final {
|
virtual Result CreateDirectory(InPointer<char> in_path) final {
|
||||||
FsPath path;
|
FsPath path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer));
|
||||||
Result rc;
|
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->CreateDirectory(path);
|
return this->base_fs->CreateDirectory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result DeleteDirectory(InPointer<char> in_path) final {
|
virtual Result DeleteDirectory(InPointer<char> in_path) final {
|
||||||
FsPath path;
|
FsPath path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer));
|
||||||
Result rc;
|
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->DeleteDirectory(path);
|
return this->base_fs->DeleteDirectory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result DeleteDirectoryRecursively(InPointer<char> in_path) final {
|
virtual Result DeleteDirectoryRecursively(InPointer<char> in_path) final {
|
||||||
FsPath path;
|
FsPath path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer));
|
||||||
Result rc;
|
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->DeleteDirectoryRecursively(path);
|
return this->base_fs->DeleteDirectoryRecursively(path);
|
||||||
}
|
}
|
||||||
@@ -272,14 +252,8 @@ class IFileSystemInterface : public IServiceObject {
|
|||||||
virtual Result RenameFile(InPointer<char> in_old_path, InPointer<char> in_new_path) final {
|
virtual Result RenameFile(InPointer<char> in_old_path, InPointer<char> in_new_path) final {
|
||||||
FsPath old_path;
|
FsPath old_path;
|
||||||
FsPath new_path;
|
FsPath new_path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&old_path, in_old_path.pointer));
|
||||||
Result rc;
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&new_path, in_new_path.pointer));
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&old_path, in_old_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&new_path, in_new_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->RenameFile(old_path, new_path);
|
return this->base_fs->RenameFile(old_path, new_path);
|
||||||
}
|
}
|
||||||
@@ -287,14 +261,8 @@ class IFileSystemInterface : public IServiceObject {
|
|||||||
virtual Result RenameDirectory(InPointer<char> in_old_path, InPointer<char> in_new_path) final {
|
virtual Result RenameDirectory(InPointer<char> in_old_path, InPointer<char> in_new_path) final {
|
||||||
FsPath old_path;
|
FsPath old_path;
|
||||||
FsPath new_path;
|
FsPath new_path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&old_path, in_old_path.pointer));
|
||||||
Result rc;
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&new_path, in_new_path.pointer));
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&old_path, in_old_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&new_path, in_new_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->RenameDirectory(old_path, new_path);
|
return this->base_fs->RenameDirectory(old_path, new_path);
|
||||||
}
|
}
|
||||||
@@ -302,54 +270,35 @@ class IFileSystemInterface : public IServiceObject {
|
|||||||
|
|
||||||
virtual Result GetEntryType(Out<u32> out_type, InPointer<char> in_path) final {
|
virtual Result GetEntryType(Out<u32> out_type, InPointer<char> in_path) final {
|
||||||
FsPath path;
|
FsPath path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer));
|
||||||
Result rc;
|
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectoryEntryType type;
|
DirectoryEntryType type;
|
||||||
rc = this->base_fs->GetEntryType(&type, path);
|
R_TRY(this->base_fs->GetEntryType(&type, path));
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
out_type.SetValue(type);
|
out_type.SetValue(type);
|
||||||
}
|
return ResultSuccess;
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result OpenFile(Out<std::shared_ptr<IFileInterface>> out_intf, InPointer<char> in_path, uint32_t mode) final {
|
virtual Result OpenFile(Out<std::shared_ptr<IFileInterface>> out_intf, InPointer<char> in_path, uint32_t mode) final {
|
||||||
FsPath path;
|
FsPath path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer));
|
||||||
|
|
||||||
std::unique_ptr<IFile> out_file;
|
std::unique_ptr<IFile> out_file;
|
||||||
|
R_TRY(this->base_fs->OpenFile(out_file, path, static_cast<OpenMode>(mode)));
|
||||||
|
|
||||||
Result rc;
|
out_intf.SetValue(std::make_shared<IFileInterface>(std::move(out_file)));
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)))) {
|
return ResultSuccess;
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = this->base_fs->OpenFile(out_file, path, static_cast<OpenMode>(mode));
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
out_intf.SetValue(std::make_shared<IFileInterface>(std::move(out_file)));
|
|
||||||
/* TODO: Nintendo checks allocation success here, should we?. */
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result OpenDirectory(Out<std::shared_ptr<IDirectoryInterface>> out_intf, InPointer<char> in_path, uint32_t mode) final {
|
virtual Result OpenDirectory(Out<std::shared_ptr<IDirectoryInterface>> out_intf, InPointer<char> in_path, uint32_t mode) final {
|
||||||
FsPath path;
|
FsPath path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer));
|
||||||
|
|
||||||
std::unique_ptr<IDirectory> out_dir;
|
std::unique_ptr<IDirectory> out_dir;
|
||||||
|
R_TRY(this->base_fs->OpenDirectory(out_dir, path, static_cast<DirectoryOpenMode>(mode)));
|
||||||
|
|
||||||
Result rc;
|
out_intf.SetValue(std::make_shared<IDirectoryInterface>(std::move(out_dir)));
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)))) {
|
return ResultSuccess;
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = this->base_fs->OpenDirectory(out_dir, path, static_cast<DirectoryOpenMode>(mode));
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
out_intf.SetValue(std::make_shared<IDirectoryInterface>(std::move(out_dir)));
|
|
||||||
/* TODO: Nintendo checks allocation success here, should we?. */
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result Commit() final {
|
virtual Result Commit() final {
|
||||||
@@ -358,81 +307,61 @@ class IFileSystemInterface : public IServiceObject {
|
|||||||
|
|
||||||
virtual Result GetFreeSpaceSize(Out<uint64_t> out_size, InPointer<char> in_path) final {
|
virtual Result GetFreeSpaceSize(Out<uint64_t> out_size, InPointer<char> in_path) final {
|
||||||
FsPath path;
|
FsPath path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer));
|
||||||
Result rc;
|
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->GetFreeSpaceSize(out_size.GetPointer(), path);
|
return this->base_fs->GetFreeSpaceSize(out_size.GetPointer(), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result GetTotalSpaceSize(Out<uint64_t> out_size, InPointer<char> in_path) final {
|
virtual Result GetTotalSpaceSize(Out<uint64_t> out_size, InPointer<char> in_path) final {
|
||||||
FsPath path;
|
FsPath path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer));
|
||||||
Result rc;
|
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->GetTotalSpaceSize(out_size.GetPointer(), path);
|
return this->base_fs->GetTotalSpaceSize(out_size.GetPointer(), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result CleanDirectoryRecursively(InPointer<char> in_path) final {
|
virtual Result CleanDirectoryRecursively(InPointer<char> in_path) final {
|
||||||
FsPath path;
|
FsPath path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer));
|
||||||
Result rc;
|
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->CleanDirectoryRecursively(path);
|
return this->base_fs->CleanDirectoryRecursively(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result GetFileTimeStampRaw(Out<FsTimeStampRaw> out_timestamp, InPointer<char> in_path) final {
|
virtual Result GetFileTimeStampRaw(Out<FsTimeStampRaw> out_timestamp, InPointer<char> in_path) final {
|
||||||
FsPath path;
|
FsPath path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer));
|
||||||
Result rc;
|
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->GetFileTimeStampRaw(out_timestamp.GetPointer(), path);
|
return this->base_fs->GetFileTimeStampRaw(out_timestamp.GetPointer(), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result QueryEntry(OutBuffer<char, BufferType_Type1> out_buffer, InBuffer<char, BufferType_Type1> in_buffer, int query, InPointer<char> in_path) final {
|
virtual Result QueryEntry(OutBuffer<char, BufferType_Type1> out_buffer, InBuffer<char, BufferType_Type1> in_buffer, int query, InPointer<char> in_path) final {
|
||||||
FsPath path;
|
FsPath path;
|
||||||
|
R_TRY(FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer));
|
||||||
Result rc;
|
|
||||||
if (R_FAILED((rc = FsPathUtils::ConvertPathForServiceObject(&path, in_path.pointer)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->QueryEntry(out_buffer.buffer, out_buffer.num_elements, in_buffer.buffer, in_buffer.num_elements, query, path);
|
return this->base_fs->QueryEntry(out_buffer.buffer, out_buffer.num_elements, in_buffer.buffer, in_buffer.num_elements, query, path);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
/* 1.0.0- */
|
/* 1.0.0- */
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_CreateFile, &IFileSystemInterface::CreateFile>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, CreateFile),
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_DeleteFile, &IFileSystemInterface::DeleteFile>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, DeleteFile),
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_CreateDirectory, &IFileSystemInterface::CreateDirectory>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, CreateDirectory),
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_DeleteDirectory, &IFileSystemInterface::DeleteDirectory>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, DeleteDirectory),
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_DeleteDirectoryRecursively, &IFileSystemInterface::DeleteDirectoryRecursively>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, DeleteDirectoryRecursively),
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_RenameFile, &IFileSystemInterface::RenameFile>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, RenameFile),
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_RenameDirectory, &IFileSystemInterface::RenameDirectory>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, RenameDirectory),
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_GetEntryType, &IFileSystemInterface::GetEntryType>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, GetEntryType),
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_OpenFile, &IFileSystemInterface::OpenFile>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, OpenFile),
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_OpenDirectory, &IFileSystemInterface::OpenDirectory>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, OpenDirectory),
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_Commit, &IFileSystemInterface::Commit>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, Commit),
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_GetFreeSpaceSize, &IFileSystemInterface::GetFreeSpaceSize>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, GetFreeSpaceSize),
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_GetTotalSpaceSize, &IFileSystemInterface::GetTotalSpaceSize>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, GetTotalSpaceSize),
|
||||||
|
|
||||||
/* 3.0.0- */
|
/* 3.0.0- */
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_CleanDirectoryRecursively, &IFileSystemInterface::CleanDirectoryRecursively, FirmwareVersion_300>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, CleanDirectoryRecursively, FirmwareVersion_300),
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_GetFileTimeStampRaw, &IFileSystemInterface::GetFileTimeStampRaw, FirmwareVersion_300>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, GetFileTimeStampRaw, FirmwareVersion_300),
|
||||||
|
|
||||||
/* 4.0.0- */
|
/* 4.0.0- */
|
||||||
MakeServiceCommandMeta<FsIFileSystemCmd_QueryEntry, &IFileSystemInterface::QueryEntry, FirmwareVersion_400>(),
|
MAKE_SERVICE_COMMAND_META(IFileSystemInterface, QueryEntry, FirmwareVersion_400),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -487,34 +416,25 @@ class ProxyFileSystem : public IFileSystem {
|
|||||||
|
|
||||||
virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) {
|
virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) {
|
||||||
FsEntryType type;
|
FsEntryType type;
|
||||||
|
R_TRY(fsFsGetEntryType(this->base_fs.get(), path.str, &type));
|
||||||
|
|
||||||
Result rc = fsFsGetEntryType(this->base_fs.get(), path.str, &type);
|
*out = static_cast<DirectoryEntryType>(static_cast<u32>(type));
|
||||||
if (R_SUCCEEDED(rc)) {
|
return ResultSuccess;
|
||||||
*out = static_cast<DirectoryEntryType>(static_cast<u32>(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
virtual Result OpenFileImpl(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) {
|
virtual Result OpenFileImpl(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) {
|
||||||
FsFile f;
|
FsFile f;
|
||||||
|
R_TRY(fsFsOpenFile(this->base_fs.get(), path.str, static_cast<int>(mode), &f));
|
||||||
|
|
||||||
Result rc = fsFsOpenFile(this->base_fs.get(), path.str, static_cast<int>(mode), &f);
|
out_file = std::make_unique<ProxyFile>(f);
|
||||||
if (R_SUCCEEDED(rc)) {
|
return ResultSuccess;
|
||||||
out_file = std::make_unique<ProxyFile>(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, const FsPath &path, DirectoryOpenMode mode) {
|
virtual Result OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, const FsPath &path, DirectoryOpenMode mode) {
|
||||||
FsDir d;
|
FsDir d;
|
||||||
|
R_TRY(fsFsOpenDirectory(this->base_fs.get(), path.str, static_cast<int>(mode), &d));
|
||||||
|
|
||||||
Result rc = fsFsOpenDirectory(this->base_fs.get(), path.str, static_cast<int>(mode), &d);
|
out_dir = std::make_unique<ProxyDirectory>(d);
|
||||||
if (R_SUCCEEDED(rc)) {
|
return ResultSuccess;
|
||||||
out_dir = std::make_unique<ProxyDirectory>(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Result CommitImpl() {
|
virtual Result CommitImpl() {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
@@ -21,15 +21,6 @@
|
|||||||
|
|
||||||
#include "../debug.hpp"
|
#include "../debug.hpp"
|
||||||
|
|
||||||
enum FsIStorageCmd : u32 {
|
|
||||||
FsIStorageCmd_Read = 0,
|
|
||||||
FsIStorageCmd_Write = 1,
|
|
||||||
FsIStorageCmd_Flush = 2,
|
|
||||||
FsIStorageCmd_SetSize = 3,
|
|
||||||
FsIStorageCmd_GetSize = 4,
|
|
||||||
FsIStorageCmd_OperateRange = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
class IStorage {
|
class IStorage {
|
||||||
public:
|
public:
|
||||||
virtual ~IStorage();
|
virtual ~IStorage();
|
||||||
@@ -47,6 +38,15 @@ class IStorage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class IStorageInterface : public IServiceObject {
|
class IStorageInterface : public IServiceObject {
|
||||||
|
private:
|
||||||
|
enum class CommandId {
|
||||||
|
Read = 0,
|
||||||
|
Write = 1,
|
||||||
|
Flush = 2,
|
||||||
|
SetSize = 3,
|
||||||
|
GetSize = 4,
|
||||||
|
OperateRange = 5,
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
IStorage *base_storage;
|
IStorage *base_storage;
|
||||||
public:
|
public:
|
||||||
@@ -57,7 +57,7 @@ class IStorageInterface : public IServiceObject {
|
|||||||
~IStorageInterface() {
|
~IStorageInterface() {
|
||||||
delete base_storage;
|
delete base_storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* Actual command API. */
|
/* Actual command API. */
|
||||||
virtual Result Read(OutBuffer<u8, BufferType_Type1> buffer, u64 offset, u64 size) final {
|
virtual Result Read(OutBuffer<u8, BufferType_Type1> buffer, u64 offset, u64 size) final {
|
||||||
@@ -81,14 +81,14 @@ class IStorageInterface : public IServiceObject {
|
|||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
/* 1.0.0- */
|
/* 1.0.0- */
|
||||||
MakeServiceCommandMeta<FsIStorageCmd_Read, &IStorageInterface::Read>(),
|
MAKE_SERVICE_COMMAND_META(IStorageInterface, Read),
|
||||||
MakeServiceCommandMeta<FsIStorageCmd_Write, &IStorageInterface::Write>(),
|
MAKE_SERVICE_COMMAND_META(IStorageInterface, Write),
|
||||||
MakeServiceCommandMeta<FsIStorageCmd_Flush, &IStorageInterface::Flush>(),
|
MAKE_SERVICE_COMMAND_META(IStorageInterface, Flush),
|
||||||
MakeServiceCommandMeta<FsIStorageCmd_SetSize, &IStorageInterface::SetSize>(),
|
MAKE_SERVICE_COMMAND_META(IStorageInterface, SetSize),
|
||||||
MakeServiceCommandMeta<FsIStorageCmd_GetSize, &IStorageInterface::GetSize>(),
|
MAKE_SERVICE_COMMAND_META(IStorageInterface, GetSize),
|
||||||
|
|
||||||
/* 4.0.0- */
|
/* 4.0.0- */
|
||||||
MakeServiceCommandMeta<FsIStorageCmd_OperateRange, &IStorageInterface::OperateRange, FirmwareVersion_400>(),
|
MAKE_SERVICE_COMMAND_META(IStorageInterface, OperateRange, FirmwareVersion_400),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -85,9 +85,9 @@ Result FsPathUtils::IsNormalized(bool *out, const char *path) {
|
|||||||
ParentDir,
|
ParentDir,
|
||||||
WindowsDriveLetter,
|
WindowsDriveLetter,
|
||||||
};
|
};
|
||||||
|
|
||||||
PathState state = PathState::Start;
|
PathState state = PathState::Start;
|
||||||
|
|
||||||
for (const char *cur = path; *cur != 0; cur++) {
|
for (const char *cur = path; *cur != 0; cur++) {
|
||||||
const char c = *cur;
|
const char c = *cur;
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@@ -145,7 +145,7 @@ Result FsPathUtils::IsNormalized(bool *out, const char *path) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case PathState::Start:
|
case PathState::Start:
|
||||||
case PathState::WindowsDriveLetter:
|
case PathState::WindowsDriveLetter:
|
||||||
@@ -160,7 +160,7 @@ Result FsPathUtils::IsNormalized(bool *out, const char *path) {
|
|||||||
*out = false;
|
*out = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,11 +169,11 @@ Result FsPathUtils::Normalize(char *out, size_t max_out_size, const char *src, s
|
|||||||
if (src[0] != '/') {
|
if (src[0] != '/') {
|
||||||
return ResultFsInvalidPathFormat;
|
return ResultFsInvalidPathFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool skip_next_sep = false;
|
bool skip_next_sep = false;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
while (src[i] != 0) {
|
while (src[i] != 0) {
|
||||||
if (src[i] == '/') {
|
if (src[i] == '/') {
|
||||||
/* Swallow separators. */
|
/* Swallow separators. */
|
||||||
@@ -181,7 +181,7 @@ Result FsPathUtils::Normalize(char *out, size_t max_out_size, const char *src, s
|
|||||||
if (src[i] == 0) {
|
if (src[i] == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle skip if needed */
|
/* Handle skip if needed */
|
||||||
if (!skip_next_sep) {
|
if (!skip_next_sep) {
|
||||||
if (len + 1 == max_out_size) {
|
if (len + 1 == max_out_size) {
|
||||||
@@ -191,28 +191,28 @@ Result FsPathUtils::Normalize(char *out, size_t max_out_size, const char *src, s
|
|||||||
}
|
}
|
||||||
return ResultFsTooLongPath;
|
return ResultFsTooLongPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
out[len++] = '/';
|
out[len++] = '/';
|
||||||
|
|
||||||
/* TODO: N has some weird windows support stuff here under a bool. */
|
/* TODO: N has some weird windows support stuff here under a bool. */
|
||||||
/* Boolean is normally false though? */
|
/* Boolean is normally false though? */
|
||||||
}
|
}
|
||||||
skip_next_sep = false;
|
skip_next_sep = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See length of current dir. */
|
/* See length of current dir. */
|
||||||
size_t dir_len = 0;
|
size_t dir_len = 0;
|
||||||
while (src[i+dir_len] != '/' && src[i+dir_len] != 0) {
|
while (src[i+dir_len] != '/' && src[i+dir_len] != 0) {
|
||||||
dir_len++;
|
dir_len++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FsPathUtils::IsCurrentDirectory(&src[i])) {
|
if (FsPathUtils::IsCurrentDirectory(&src[i])) {
|
||||||
skip_next_sep = true;
|
skip_next_sep = true;
|
||||||
} else if (FsPathUtils::IsParentDirectory(&src[i])) {
|
} else if (FsPathUtils::IsParentDirectory(&src[i])) {
|
||||||
if (len == 1) {
|
if (len == 1) {
|
||||||
return ResultFsDirectoryUnobtainable;
|
return ResultFsDirectoryUnobtainable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Walk up a directory. */
|
/* Walk up a directory. */
|
||||||
len -= 2;
|
len -= 2;
|
||||||
while (out[len] != '/') {
|
while (out[len] != '/') {
|
||||||
@@ -236,33 +236,34 @@ Result FsPathUtils::Normalize(char *out, size_t max_out_size, const char *src, s
|
|||||||
return ResultFsTooLongPath;
|
return ResultFsTooLongPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i += dir_len;
|
i += dir_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skip_next_sep) {
|
if (skip_next_sep) {
|
||||||
len--;
|
len--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len == 0 && max_out_size) {
|
if (len == 0 && max_out_size) {
|
||||||
out[len++] = '/';
|
out[len++] = '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_out_size < len - 1) {
|
if (max_out_size < len - 1) {
|
||||||
return ResultFsTooLongPath;
|
return ResultFsTooLongPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NULL terminate. */
|
/* NULL terminate. */
|
||||||
out[len] = 0;
|
out[len] = 0;
|
||||||
if (out_len != nullptr) {
|
if (out_len != nullptr) {
|
||||||
*out_len = len;
|
*out_len = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assert normalized. */
|
/* Assert normalized. */
|
||||||
bool normalized = false;
|
bool normalized = false;
|
||||||
if (R_FAILED(FsPathUtils::IsNormalized(&normalized, out)) || !normalized) {
|
R_ASSERT(FsPathUtils::IsNormalized(&normalized, out));
|
||||||
|
if (!normalized) {
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,22 +49,22 @@ class FsPathUtils {
|
|||||||
public:
|
public:
|
||||||
static Result VerifyPath(const char *path, size_t max_path_len, size_t max_name_len);
|
static Result VerifyPath(const char *path, size_t max_path_len, size_t max_name_len);
|
||||||
static Result ConvertPathForServiceObject(FsPath *out, const char *path);
|
static Result ConvertPathForServiceObject(FsPath *out, const char *path);
|
||||||
|
|
||||||
static Result IsNormalized(bool *out, const char *path);
|
static Result IsNormalized(bool *out, const char *path);
|
||||||
static Result Normalize(char *out, size_t max_out_size, const char *src, size_t *out_size);
|
static Result Normalize(char *out, size_t max_out_size, const char *src, size_t *out_size);
|
||||||
|
|
||||||
static bool IsWindowsDriveLetter(const char c) {
|
static bool IsWindowsDriveLetter(const char c) {
|
||||||
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
|
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsCurrentDirectory(const char *path) {
|
static bool IsCurrentDirectory(const char *path) {
|
||||||
return path[0] == '.' && (path[1] == 0 || path[1] == '/');
|
return path[0] == '.' && (path[1] == 0 || path[1] == '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsParentDirectory(const char *path) {
|
static bool IsParentDirectory(const char *path) {
|
||||||
return path[0] == '.' && path[1] == '.' && (path[2] == 0 || path[2] == '/');
|
return path[0] == '.' && path[1] == '.' && (path[2] == 0 || path[2] == '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsWindowsAbsolutePath(const char *path) {
|
static bool IsWindowsAbsolutePath(const char *path) {
|
||||||
/* Nintendo uses this in path comparisons... */
|
/* Nintendo uses this in path comparisons... */
|
||||||
return IsWindowsDriveLetter(path[0]) && path[1] == ':';
|
return IsWindowsDriveLetter(path[0]) && path[1] == ':';
|
||||||
|
|||||||
@@ -100,12 +100,10 @@ Result FsSaveUtils::GetSaveDataTypeString(const char **out_str, u8 save_data_typ
|
|||||||
|
|
||||||
Result FsSaveUtils::GetSaveDataDirectoryPath(FsPath &out_path, u8 space_id, u8 save_data_type, u64 title_id, u128 user_id, u64 save_id) {
|
Result FsSaveUtils::GetSaveDataDirectoryPath(FsPath &out_path, u8 space_id, u8 save_data_type, u64 title_id, u128 user_id, u64 save_id) {
|
||||||
const char *space_id_str, *save_type_str;
|
const char *space_id_str, *save_type_str;
|
||||||
Result rc;
|
|
||||||
|
|
||||||
/* Get space_id, save_data_type strings. */
|
/* Get space_id, save_data_type strings. */
|
||||||
if (R_FAILED((rc = GetSaveDataSpaceIdString(&space_id_str, space_id))) || R_FAILED((rc = GetSaveDataTypeString(&save_type_str, save_data_type)))) {
|
R_TRY(GetSaveDataSpaceIdString(&space_id_str, space_id));
|
||||||
return rc;
|
R_TRY(GetSaveDataTypeString(&save_type_str, save_data_type));
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear and initialize the path. */
|
/* Clear and initialize the path. */
|
||||||
std::memset(&out_path, 0, sizeof(out_path));
|
std::memset(&out_path, 0, sizeof(out_path));
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "fs_shim.h"
|
#include "fs_shim.h"
|
||||||
@@ -79,7 +79,7 @@ Result fsOpenDataStorageByCurrentProcessFwd(Service* s, FsStorage* out) {
|
|||||||
u64 magic;
|
u64 magic;
|
||||||
u64 result;
|
u64 result;
|
||||||
} *resp;
|
} *resp;
|
||||||
|
|
||||||
serviceIpcParse(s, &r, sizeof(*resp));
|
serviceIpcParse(s, &r, sizeof(*resp));
|
||||||
resp = r.Raw;
|
resp = r.Raw;
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorageId storage_id, u64 data
|
|||||||
u64 magic;
|
u64 magic;
|
||||||
u64 result;
|
u64 result;
|
||||||
} *resp;
|
} *resp;
|
||||||
|
|
||||||
serviceIpcParse(s, &r, sizeof(*resp));
|
serviceIpcParse(s, &r, sizeof(*resp));
|
||||||
resp = r.Raw;
|
resp = r.Raw;
|
||||||
|
|
||||||
|
|||||||
@@ -26,33 +26,29 @@ Result SubDirectoryFileSystem::Initialize(const char *bp) {
|
|||||||
if (strnlen(bp, FS_MAX_PATH) >= FS_MAX_PATH) {
|
if (strnlen(bp, FS_MAX_PATH) >= FS_MAX_PATH) {
|
||||||
return ResultFsTooLongPath;
|
return ResultFsTooLongPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Normalize the path. */
|
/* Normalize the path. */
|
||||||
char normal_path[FS_MAX_PATH + 1];
|
char normal_path[FS_MAX_PATH + 1];
|
||||||
size_t normal_path_len;
|
size_t normal_path_len;
|
||||||
Result rc = FsPathUtils::Normalize(normal_path, sizeof(normal_path), bp, &normal_path_len);
|
R_ASSERT(FsPathUtils::Normalize(normal_path, sizeof(normal_path), bp, &normal_path_len));
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
/* N calls svcBreak here. */
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure terminating '/' */
|
/* Ensure terminating '/' */
|
||||||
if (normal_path[normal_path_len-1] != '/') {
|
if (normal_path[normal_path_len-1] != '/') {
|
||||||
if (normal_path_len + 2 > sizeof(normal_path)) {
|
if (normal_path_len + 2 > sizeof(normal_path)) {
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
strncat(normal_path, "/", 2);
|
strncat(normal_path, "/", 2);
|
||||||
normal_path[sizeof(normal_path)-1] = 0;
|
normal_path[sizeof(normal_path)-1] = 0;
|
||||||
normal_path_len++;
|
normal_path_len++;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->base_path_len = normal_path_len + 1;
|
this->base_path_len = normal_path_len + 1;
|
||||||
this->base_path = reinterpret_cast<char *>(malloc(this->base_path_len));
|
this->base_path = reinterpret_cast<char *>(malloc(this->base_path_len));
|
||||||
if (this->base_path == nullptr) {
|
if (this->base_path == nullptr) {
|
||||||
return ResultFsAllocationFailureInSubDirectoryFileSystem;
|
return ResultFsAllocationFailureInSubDirectoryFileSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::strncpy(this->base_path, normal_path, this->base_path_len);
|
std::strncpy(this->base_path, normal_path, this->base_path_len);
|
||||||
this->base_path[this->base_path_len-1] = 0;
|
this->base_path[this->base_path_len-1] = 0;
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
@@ -62,130 +58,84 @@ Result SubDirectoryFileSystem::GetFullPath(char *out, size_t out_size, const cha
|
|||||||
if (this->base_path_len + strnlen(relative_path, FS_MAX_PATH) > out_size) {
|
if (this->base_path_len + strnlen(relative_path, FS_MAX_PATH) > out_size) {
|
||||||
return ResultFsTooLongPath;
|
return ResultFsTooLongPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy base path. */
|
/* Copy base path. */
|
||||||
std::strncpy(out, this->base_path, out_size);
|
std::strncpy(out, this->base_path, out_size);
|
||||||
out[out_size-1] = 0;
|
out[out_size-1] = 0;
|
||||||
|
|
||||||
/* Normalize it. */
|
/* Normalize it. */
|
||||||
return FsPathUtils::Normalize(out + this->base_path_len - 2, out_size - (this->base_path_len - 2), relative_path, nullptr);
|
return FsPathUtils::Normalize(out + this->base_path_len - 2, out_size - (this->base_path_len - 2), relative_path, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::CreateFileImpl(const FsPath &path, uint64_t size, int flags) {
|
Result SubDirectoryFileSystem::CreateFileImpl(const FsPath &path, uint64_t size, int flags) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->CreateFile(full_path, size, flags);
|
return this->base_fs->CreateFile(full_path, size, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::DeleteFileImpl(const FsPath &path) {
|
Result SubDirectoryFileSystem::DeleteFileImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->DeleteFile(full_path);
|
return this->base_fs->DeleteFile(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::CreateDirectoryImpl(const FsPath &path) {
|
Result SubDirectoryFileSystem::CreateDirectoryImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->CreateDirectory(full_path);
|
return this->base_fs->CreateDirectory(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::DeleteDirectoryImpl(const FsPath &path) {
|
Result SubDirectoryFileSystem::DeleteDirectoryImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->DeleteDirectory(full_path);
|
return this->base_fs->DeleteDirectory(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::DeleteDirectoryRecursivelyImpl(const FsPath &path) {
|
Result SubDirectoryFileSystem::DeleteDirectoryRecursivelyImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->DeleteDirectoryRecursively(full_path);
|
return this->base_fs->DeleteDirectoryRecursively(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::RenameFileImpl(const FsPath &old_path, const FsPath &new_path) {
|
Result SubDirectoryFileSystem::RenameFileImpl(const FsPath &old_path, const FsPath &new_path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_old_path, full_new_path;
|
FsPath full_old_path, full_new_path;
|
||||||
|
R_TRY(GetFullPath(full_old_path, old_path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_old_path, old_path)))) {
|
R_TRY(GetFullPath(full_new_path, new_path));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED((rc = GetFullPath(full_new_path, new_path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->RenameFile(full_old_path, full_new_path);
|
return this->base_fs->RenameFile(full_old_path, full_new_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) {
|
Result SubDirectoryFileSystem::RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_old_path, full_new_path;
|
FsPath full_old_path, full_new_path;
|
||||||
|
R_TRY(GetFullPath(full_old_path, old_path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_old_path, old_path)))) {
|
R_TRY(GetFullPath(full_new_path, new_path));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED((rc = GetFullPath(full_new_path, new_path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->RenameDirectory(full_old_path, full_new_path);
|
return this->base_fs->RenameDirectory(full_old_path, full_new_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) {
|
Result SubDirectoryFileSystem::GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->GetEntryType(out, full_path);
|
return this->base_fs->GetEntryType(out, full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::OpenFileImpl(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) {
|
Result SubDirectoryFileSystem::OpenFileImpl(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->OpenFile(out_file, full_path, mode);
|
return this->base_fs->OpenFile(out_file, full_path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, const FsPath &path, DirectoryOpenMode mode) {
|
Result SubDirectoryFileSystem::OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, const FsPath &path, DirectoryOpenMode mode) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->OpenDirectory(out_dir, full_path, mode);
|
return this->base_fs->OpenDirectory(out_dir, full_path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,56 +144,36 @@ Result SubDirectoryFileSystem::CommitImpl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) {
|
Result SubDirectoryFileSystem::GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->GetFreeSpaceSize(out, full_path);
|
return this->base_fs->GetFreeSpaceSize(out, full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) {
|
Result SubDirectoryFileSystem::GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->GetTotalSpaceSize(out, full_path);
|
return this->base_fs->GetTotalSpaceSize(out, full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::CleanDirectoryRecursivelyImpl(const FsPath &path) {
|
Result SubDirectoryFileSystem::CleanDirectoryRecursivelyImpl(const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->CleanDirectoryRecursively(full_path);
|
return this->base_fs->CleanDirectoryRecursively(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::GetFileTimeStampRawImpl(FsTimeStampRaw *out, const FsPath &path) {
|
Result SubDirectoryFileSystem::GetFileTimeStampRawImpl(FsTimeStampRaw *out, const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->GetFileTimeStampRaw(out, full_path);
|
return this->base_fs->GetFileTimeStampRaw(out, full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SubDirectoryFileSystem::QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, const FsPath &path) {
|
Result SubDirectoryFileSystem::QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, const FsPath &path) {
|
||||||
Result rc;
|
|
||||||
FsPath full_path;
|
FsPath full_path;
|
||||||
|
R_TRY(GetFullPath(full_path, path));
|
||||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->base_fs->QueryEntry(out, out_size, in, in_size, query, full_path);
|
return this->base_fs->QueryEntry(out, out_size, in, in_size, query, full_path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,20 +26,14 @@ class SubDirectoryFileSystem : public IFileSystem {
|
|||||||
std::shared_ptr<IFileSystem> base_fs;
|
std::shared_ptr<IFileSystem> base_fs;
|
||||||
char *base_path = nullptr;
|
char *base_path = nullptr;
|
||||||
size_t base_path_len = 0;
|
size_t base_path_len = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SubDirectoryFileSystem(IFileSystem *fs, const char *bp) : base_fs(fs) {
|
SubDirectoryFileSystem(IFileSystem *fs, const char *bp) : base_fs(fs) {
|
||||||
Result rc = this->Initialize(bp);
|
R_ASSERT(this->Initialize(bp));
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SubDirectoryFileSystem(std::shared_ptr<IFileSystem> fs, const char *bp) : base_fs(fs) {
|
SubDirectoryFileSystem(std::shared_ptr<IFileSystem> fs, const char *bp) : base_fs(fs) {
|
||||||
Result rc = this->Initialize(bp);
|
R_ASSERT(this->Initialize(bp));
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -48,7 +42,7 @@ class SubDirectoryFileSystem : public IFileSystem {
|
|||||||
free(this->base_path);
|
free(this->base_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Result Initialize(const char *bp);
|
Result Initialize(const char *bp);
|
||||||
protected:
|
protected:
|
||||||
@@ -56,7 +50,7 @@ class SubDirectoryFileSystem : public IFileSystem {
|
|||||||
Result GetFullPath(FsPath &full_path, const FsPath &relative_path) {
|
Result GetFullPath(FsPath &full_path, const FsPath &relative_path) {
|
||||||
return GetFullPath(full_path.str, sizeof(full_path.str), relative_path.str);
|
return GetFullPath(full_path.str, sizeof(full_path.str), relative_path.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual Result CreateFileImpl(const FsPath &path, uint64_t size, int flags) override;
|
virtual Result CreateFileImpl(const FsPath &path, uint64_t size, int flags) override;
|
||||||
virtual Result DeleteFileImpl(const FsPath &path) override;
|
virtual Result DeleteFileImpl(const FsPath &path) override;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
@@ -38,16 +38,15 @@ bool Boot0Storage::CanModifyBctPubks() {
|
|||||||
|
|
||||||
Result Boot0Storage::Read(void *_buffer, size_t size, u64 offset) {
|
Result Boot0Storage::Read(void *_buffer, size_t size, u64 offset) {
|
||||||
std::scoped_lock<HosMutex> lk{g_boot0_mutex};
|
std::scoped_lock<HosMutex> lk{g_boot0_mutex};
|
||||||
|
|
||||||
return Base::Read(_buffer, size, offset);
|
return Base::Read(_buffer, size, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Boot0Storage::Write(void *_buffer, size_t size, u64 offset) {
|
Result Boot0Storage::Write(void *_buffer, size_t size, u64 offset) {
|
||||||
std::scoped_lock<HosMutex> lk{g_boot0_mutex};
|
std::scoped_lock<HosMutex> lk{g_boot0_mutex};
|
||||||
|
|
||||||
Result rc = ResultSuccess;
|
|
||||||
u8 *buffer = static_cast<u8 *>(_buffer);
|
u8 *buffer = static_cast<u8 *>(_buffer);
|
||||||
|
|
||||||
/* Protect the keyblob region from writes. */
|
/* Protect the keyblob region from writes. */
|
||||||
if (offset <= EksStart) {
|
if (offset <= EksStart) {
|
||||||
if (offset + size < EksStart) {
|
if (offset + size < EksStart) {
|
||||||
@@ -59,9 +58,7 @@ Result Boot0Storage::Write(void *_buffer, size_t size, u64 offset) {
|
|||||||
} else {
|
} else {
|
||||||
/* Perform portion of write falling past end of keyblobs. */
|
/* Perform portion of write falling past end of keyblobs. */
|
||||||
const u64 diff = EksEnd - offset;
|
const u64 diff = EksEnd - offset;
|
||||||
if (R_FAILED((rc = Base::Write(buffer + diff, size - diff, EksEnd)))) {
|
R_TRY(Base::Write(buffer + diff, size - diff, EksEnd));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
/* Adjust size to avoid writing end of data. */
|
/* Adjust size to avoid writing end of data. */
|
||||||
size = EksStart - offset;
|
size = EksStart - offset;
|
||||||
}
|
}
|
||||||
@@ -81,30 +78,26 @@ Result Boot0Storage::Write(void *_buffer, size_t size, u64 offset) {
|
|||||||
/* Fall through, no need to do anything here. */
|
/* Fall through, no need to do anything here. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We care about protecting autorcm from NS. */
|
/* We care about protecting autorcm from NS. */
|
||||||
if (CanModifyBctPubks() || offset >= BctEndOffset || (offset + BctSize >= BctEndOffset && offset % BctSize >= BctPubkEnd)) {
|
if (CanModifyBctPubks() || offset >= BctEndOffset || (offset + BctSize >= BctEndOffset && offset % BctSize >= BctPubkEnd)) {
|
||||||
return Base::Write(buffer, size, offset);
|
return Base::Write(buffer, size, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First, let's deal with the data past the end. */
|
/* First, let's deal with the data past the end. */
|
||||||
if (offset + size >= BctEndOffset) {
|
if (offset + size >= BctEndOffset) {
|
||||||
const u64 diff = BctEndOffset - offset;
|
const u64 diff = BctEndOffset - offset;
|
||||||
if (R_FAILED((rc = ProxyStorage::Write(buffer + diff, size - diff, BctEndOffset)))) {
|
R_TRY(ProxyStorage::Write(buffer + diff, size - diff, BctEndOffset));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
size = diff;
|
size = diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read in the current BCT region. */
|
/* Read in the current BCT region. */
|
||||||
if (R_FAILED((rc = ProxyStorage::Read(g_boot0_bct_buffer, BctEndOffset, 0)))) {
|
R_TRY(ProxyStorage::Read(g_boot0_bct_buffer, BctEndOffset, 0));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the bct buffer. */
|
/* Update the bct buffer. */
|
||||||
for (u64 cur_ofs = offset; cur_ofs < BctEndOffset && cur_ofs < offset + size; cur_ofs++) {
|
for (u64 cur_ofs = offset; cur_ofs < BctEndOffset && cur_ofs < offset + size; cur_ofs++) {
|
||||||
const u64 cur_bct_rel_ofs = cur_ofs % BctSize;
|
const u64 cur_bct_rel_ofs = cur_ofs % BctSize;
|
||||||
@@ -112,6 +105,6 @@ Result Boot0Storage::Write(void *_buffer, size_t size, u64 offset) {
|
|||||||
g_boot0_bct_buffer[cur_ofs] = buffer[cur_ofs - offset];
|
g_boot0_bct_buffer[cur_ofs] = buffer[cur_ofs - offset];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ProxyStorage::Write(g_boot0_bct_buffer, BctEndOffset, 0);
|
return ProxyStorage::Write(g_boot0_bct_buffer, BctEndOffset, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
#include "fs_istorage.hpp"
|
#include "fs_istorage.hpp"
|
||||||
|
|
||||||
/* Represents a sectored storage. */
|
/* Represents a sectored storage. */
|
||||||
template<u64 SectorSize>
|
template<u64 SectorSize>
|
||||||
class SectoredProxyStorage : public ProxyStorage {
|
class SectoredProxyStorage : public ProxyStorage {
|
||||||
private:
|
private:
|
||||||
u64 cur_seek = 0;
|
u64 cur_seek = 0;
|
||||||
@@ -39,19 +39,16 @@ class SectoredProxyStorage : public ProxyStorage {
|
|||||||
SectoredProxyStorage(FsStorage s) : ProxyStorage(s) { }
|
SectoredProxyStorage(FsStorage s) : ProxyStorage(s) { }
|
||||||
public:
|
public:
|
||||||
virtual Result Read(void *_buffer, size_t size, u64 offset) override {
|
virtual Result Read(void *_buffer, size_t size, u64 offset) override {
|
||||||
Result rc = ResultSuccess;
|
|
||||||
u8 *buffer = static_cast<u8 *>(_buffer);
|
u8 *buffer = static_cast<u8 *>(_buffer);
|
||||||
this->Seek(offset);
|
this->Seek(offset);
|
||||||
|
|
||||||
if (this->cur_sector_ofs == 0 && size % SectorSize == 0) {
|
if (this->cur_sector_ofs == 0 && size % SectorSize == 0) {
|
||||||
/* Fast case. */
|
/* Fast case. */
|
||||||
return ProxyStorage::Read(buffer, size, offset);
|
return ProxyStorage::Read(buffer, size, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, this->cur_seek)))) {
|
R_TRY(ProxyStorage::Read(this->sector_buf, SectorSize, this->cur_seek));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size + this->cur_sector_ofs <= SectorSize) {
|
if (size + this->cur_sector_ofs <= SectorSize) {
|
||||||
memcpy(buffer, sector_buf + this->cur_sector_ofs, size);
|
memcpy(buffer, sector_buf + this->cur_sector_ofs, size);
|
||||||
} else {
|
} else {
|
||||||
@@ -59,90 +56,77 @@ class SectoredProxyStorage : public ProxyStorage {
|
|||||||
size_t ofs = SectorSize - this->cur_sector_ofs;
|
size_t ofs = SectorSize - this->cur_sector_ofs;
|
||||||
memcpy(buffer, sector_buf + this->cur_sector_ofs, ofs);
|
memcpy(buffer, sector_buf + this->cur_sector_ofs, ofs);
|
||||||
size -= ofs;
|
size -= ofs;
|
||||||
|
|
||||||
/* We're guaranteed alignment, here. */
|
/* We're guaranteed alignment, here. */
|
||||||
const size_t aligned_remaining_size = size - (size % SectorSize);
|
const size_t aligned_remaining_size = size - (size % SectorSize);
|
||||||
if (aligned_remaining_size) {
|
if (aligned_remaining_size) {
|
||||||
if (R_FAILED((rc = ProxyStorage::Read(buffer + ofs, aligned_remaining_size, offset + ofs)))) {
|
R_TRY(ProxyStorage::Read(buffer + ofs, aligned_remaining_size, offset + ofs));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
ofs += aligned_remaining_size;
|
ofs += aligned_remaining_size;
|
||||||
size -= aligned_remaining_size;
|
size -= aligned_remaining_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read any leftover data. */
|
/* Read any leftover data. */
|
||||||
if (size) {
|
if (size) {
|
||||||
if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, offset + ofs)))) {
|
R_TRY(ProxyStorage::Read(this->sector_buf, SectorSize, offset + ofs));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
memcpy(buffer + ofs, sector_buf, size);
|
memcpy(buffer + ofs, sector_buf, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return ResultSuccess;
|
||||||
};
|
}
|
||||||
|
|
||||||
virtual Result Write(void *_buffer, size_t size, u64 offset) override {
|
virtual Result Write(void *_buffer, size_t size, u64 offset) override {
|
||||||
Result rc = ResultSuccess;
|
|
||||||
u8 *buffer = static_cast<u8 *>(_buffer);
|
u8 *buffer = static_cast<u8 *>(_buffer);
|
||||||
this->Seek(offset);
|
this->Seek(offset);
|
||||||
|
|
||||||
if (this->cur_sector_ofs == 0 && size % SectorSize == 0) {
|
if (this->cur_sector_ofs == 0 && size % SectorSize == 0) {
|
||||||
/* Fast case. */
|
/* Fast case. */
|
||||||
return ProxyStorage::Write(buffer, size, offset);
|
return ProxyStorage::Write(buffer, size, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, this->cur_seek)))) {
|
R_TRY(ProxyStorage::Read(this->sector_buf, SectorSize, this->cur_seek));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (size + this->cur_sector_ofs <= SectorSize) {
|
if (size + this->cur_sector_ofs <= SectorSize) {
|
||||||
memcpy(this->sector_buf + this->cur_sector_ofs, buffer, size);
|
memcpy(this->sector_buf + this->cur_sector_ofs, buffer, size);
|
||||||
rc = ProxyStorage::Write(this->sector_buf, SectorSize, this->cur_seek);
|
R_TRY(ProxyStorage::Write(this->sector_buf, SectorSize, this->cur_seek));
|
||||||
} else {
|
} else {
|
||||||
/* Leaving the sector... */
|
/* Leaving the sector... */
|
||||||
size_t ofs = SectorSize - this->cur_sector_ofs;
|
size_t ofs = SectorSize - this->cur_sector_ofs;
|
||||||
memcpy(this->sector_buf + this->cur_sector_ofs, buffer, ofs);
|
memcpy(this->sector_buf + this->cur_sector_ofs, buffer, ofs);
|
||||||
if (R_FAILED((rc = ProxyStorage::Write(this->sector_buf, ofs, this->cur_seek)))) {
|
R_TRY(ProxyStorage::Write(this->sector_buf, ofs, this->cur_seek));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
size -= ofs;
|
size -= ofs;
|
||||||
|
|
||||||
/* We're guaranteed alignment, here. */
|
/* We're guaranteed alignment, here. */
|
||||||
const size_t aligned_remaining_size = size - (size % SectorSize);
|
const size_t aligned_remaining_size = size - (size % SectorSize);
|
||||||
if (aligned_remaining_size) {
|
if (aligned_remaining_size) {
|
||||||
if (R_FAILED((rc = ProxyStorage::Write(buffer + ofs, aligned_remaining_size, offset + ofs)))) {
|
R_TRY(ProxyStorage::Write(buffer + ofs, aligned_remaining_size, offset + ofs));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
ofs += aligned_remaining_size;
|
ofs += aligned_remaining_size;
|
||||||
size -= aligned_remaining_size;
|
size -= aligned_remaining_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write any leftover data. */
|
/* Write any leftover data. */
|
||||||
if (size) {
|
if (size) {
|
||||||
if (R_FAILED((rc = ProxyStorage::Read(this->sector_buf, SectorSize, offset + ofs)))) {
|
R_TRY(ProxyStorage::Read(this->sector_buf, SectorSize, offset + ofs));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
memcpy(this->sector_buf, buffer + ofs, size);
|
memcpy(this->sector_buf, buffer + ofs, size);
|
||||||
rc = ProxyStorage::Write(this->sector_buf, SectorSize, this->cur_seek);
|
R_TRY(ProxyStorage::Write(this->sector_buf, SectorSize, this->cur_seek));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return ResultSuccess;
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Represents an RCM-preserving BOOT0 partition. */
|
/* Represents an RCM-preserving BOOT0 partition. */
|
||||||
class Boot0Storage : public SectoredProxyStorage<0x200> {
|
class Boot0Storage : public SectoredProxyStorage<0x200> {
|
||||||
using Base = SectoredProxyStorage<0x200>;
|
using Base = SectoredProxyStorage<0x200>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr u64 BctEndOffset = 0xFC000;
|
static constexpr u64 BctEndOffset = 0xFC000;
|
||||||
static constexpr u64 BctSize = 0x4000;
|
static constexpr u64 BctSize = 0x4000;
|
||||||
static constexpr u64 BctPubkStart = 0x210;
|
static constexpr u64 BctPubkStart = 0x210;
|
||||||
static constexpr u64 BctPubkSize = 0x100;
|
static constexpr u64 BctPubkSize = 0x100;
|
||||||
static constexpr u64 BctPubkEnd = BctPubkStart + BctPubkSize;
|
static constexpr u64 BctPubkEnd = BctPubkStart + BctPubkSize;
|
||||||
|
|
||||||
static constexpr u64 EksStart = 0x180000;
|
static constexpr u64 EksStart = 0x180000;
|
||||||
static constexpr u64 EksSize = 0x4000;
|
static constexpr u64 EksSize = 0x4000;
|
||||||
static constexpr u64 EksEnd = EksStart + EksSize;
|
static constexpr u64 EksEnd = EksStart + EksSize;
|
||||||
@@ -154,6 +138,6 @@ class Boot0Storage : public SectoredProxyStorage<0x200> {
|
|||||||
Boot0Storage(FsStorage *s, u64 t) : Base(s), title_id(t) { }
|
Boot0Storage(FsStorage *s, u64 t) : Base(s), title_id(t) { }
|
||||||
Boot0Storage(FsStorage s, u64 t) : Base(s), title_id(t) { }
|
Boot0Storage(FsStorage s, u64 t) : Base(s), title_id(t) { }
|
||||||
public:
|
public:
|
||||||
virtual Result Read(void *_buffer, size_t size, u64 offset) override;
|
virtual Result Read(void *_buffer, size_t size, u64 offset) override;
|
||||||
virtual Result Write(void *_buffer, size_t size, u64 offset) override;
|
virtual Result Write(void *_buffer, size_t size, u64 offset) override;
|
||||||
};
|
};
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ Result LayeredRomFS::Read(void *buffer, size_t size, u64 offset) {
|
|||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Validate size. */
|
/* Validate size. */
|
||||||
u64 virt_size = (*this->p_source_infos)[this->p_source_infos->size() - 1].virtual_offset + (*this->p_source_infos)[this->p_source_infos->size() - 1].size;
|
u64 virt_size = (*this->p_source_infos)[this->p_source_infos->size() - 1].virtual_offset + (*this->p_source_infos)[this->p_source_infos->size() - 1].size;
|
||||||
if (offset >= virt_size) {
|
if (offset >= virt_size) {
|
||||||
@@ -77,8 +77,7 @@ Result LayeredRomFS::Read(void *buffer, size_t size, u64 offset) {
|
|||||||
low = mid + 1;
|
low = mid + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result rc;
|
|
||||||
size_t read_so_far = 0;
|
size_t read_so_far = 0;
|
||||||
while (read_so_far < size) {
|
while (read_so_far < size) {
|
||||||
RomFSSourceInfo *cur_source = &((*this->p_source_infos)[cur_source_ind]);
|
RomFSSourceInfo *cur_source = &((*this->p_source_infos)[cur_source_ind]);
|
||||||
@@ -91,15 +90,11 @@ Result LayeredRomFS::Read(void *buffer, size_t size, u64 offset) {
|
|||||||
case RomFSDataSource::MetaData:
|
case RomFSDataSource::MetaData:
|
||||||
{
|
{
|
||||||
FsFile file;
|
FsFile file;
|
||||||
if (R_FAILED((rc = Utils::OpenSdFileForAtmosphere(this->title_id, ROMFS_METADATA_FILE_PATH, FS_OPEN_READ, &file)))) {
|
R_ASSERT(Utils::OpenSdFileForAtmosphere(this->title_id, ROMFS_METADATA_FILE_PATH, FS_OPEN_READ, &file));
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
size_t out_read;
|
size_t out_read;
|
||||||
if (R_FAILED((rc = fsFileRead(&file, (offset - cur_source->virtual_offset), (void *)((uintptr_t)buffer + read_so_far), cur_read_size, FS_READOPTION_NONE, &out_read)))) {
|
R_ASSERT(fsFileRead(&file, (offset - cur_source->virtual_offset), (void *)((uintptr_t)buffer + read_so_far), cur_read_size, FS_READOPTION_NONE, &out_read));
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
if (out_read != cur_read_size) {
|
if (out_read != cur_read_size) {
|
||||||
Reboot();
|
std::abort();
|
||||||
}
|
}
|
||||||
fsFileClose(&file);
|
fsFileClose(&file);
|
||||||
}
|
}
|
||||||
@@ -107,15 +102,11 @@ Result LayeredRomFS::Read(void *buffer, size_t size, u64 offset) {
|
|||||||
case RomFSDataSource::LooseFile:
|
case RomFSDataSource::LooseFile:
|
||||||
{
|
{
|
||||||
FsFile file;
|
FsFile file;
|
||||||
if (R_FAILED((rc = Utils::OpenRomFSSdFile(this->title_id, cur_source->loose_source_info.path, FS_OPEN_READ, &file)))) {
|
R_ASSERT(Utils::OpenRomFSSdFile(this->title_id, cur_source->loose_source_info.path, FS_OPEN_READ, &file));
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
size_t out_read;
|
size_t out_read;
|
||||||
if (R_FAILED((rc = fsFileRead(&file, (offset - cur_source->virtual_offset), (void *)((uintptr_t)buffer + read_so_far), cur_read_size, FS_READOPTION_NONE, &out_read)))) {
|
R_ASSERT(fsFileRead(&file, (offset - cur_source->virtual_offset), (void *)((uintptr_t)buffer + read_so_far), cur_read_size, FS_READOPTION_NONE, &out_read));
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
if (out_read != cur_read_size) {
|
if (out_read != cur_read_size) {
|
||||||
Reboot();
|
std::abort();
|
||||||
}
|
}
|
||||||
fsFileClose(&file);
|
fsFileClose(&file);
|
||||||
}
|
}
|
||||||
@@ -127,23 +118,16 @@ Result LayeredRomFS::Read(void *buffer, size_t size, u64 offset) {
|
|||||||
break;
|
break;
|
||||||
case RomFSDataSource::BaseRomFS:
|
case RomFSDataSource::BaseRomFS:
|
||||||
{
|
{
|
||||||
if (R_FAILED((rc = this->storage_romfs->Read((void *)((uintptr_t)buffer + read_so_far), cur_read_size, cur_source->base_source_info.offset + (offset - cur_source->virtual_offset))))) {
|
R_ASSERT(this->storage_romfs->Read((void *)((uintptr_t)buffer + read_so_far), cur_read_size, cur_source->base_source_info.offset + (offset - cur_source->virtual_offset)));
|
||||||
/* TODO: Can this ever happen? */
|
|
||||||
/* fatalSimple(rc); */
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RomFSDataSource::FileRomFS:
|
case RomFSDataSource::FileRomFS:
|
||||||
{
|
{
|
||||||
if (R_FAILED((rc = this->file_romfs->Read((void *)((uintptr_t)buffer + read_so_far), cur_read_size, cur_source->base_source_info.offset + (offset - cur_source->virtual_offset))))) {
|
R_ASSERT(this->file_romfs->Read((void *)((uintptr_t)buffer + read_so_far), cur_read_size, cur_source->base_source_info.offset + (offset - cur_source->virtual_offset)));
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* TODO: Better error. */
|
std::abort();
|
||||||
fatalSimple(ResultKernelConnectionClosed);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
read_so_far += cur_read_size;
|
read_so_far += cur_read_size;
|
||||||
@@ -157,7 +141,7 @@ Result LayeredRomFS::Read(void *buffer, size_t size, u64 offset) {
|
|||||||
offset = ((*this->p_source_infos)[cur_source_ind]).virtual_offset;
|
offset = ((*this->p_source_infos)[cur_source_ind]).virtual_offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
Result LayeredRomFS::GetSize(u64 *out_size) {
|
Result LayeredRomFS::GetSize(u64 *out_size) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
@@ -32,11 +32,11 @@ class LayeredRomFS : public IROStorage {
|
|||||||
/* Information about the merged RomFS. */
|
/* Information about the merged RomFS. */
|
||||||
u64 title_id;
|
u64 title_id;
|
||||||
std::shared_ptr<std::vector<RomFSSourceInfo>> p_source_infos;
|
std::shared_ptr<std::vector<RomFSSourceInfo>> p_source_infos;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LayeredRomFS(std::shared_ptr<IROStorage> s_r, std::shared_ptr<IROStorage> f_r, u64 tid);
|
LayeredRomFS(std::shared_ptr<IROStorage> s_r, std::shared_ptr<IROStorage> f_r, u64 tid);
|
||||||
virtual ~LayeredRomFS() = default;
|
virtual ~LayeredRomFS() = default;
|
||||||
|
|
||||||
virtual Result Read(void *buffer, size_t size, u64 offset) override;
|
virtual Result Read(void *buffer, size_t size, u64 offset) override;
|
||||||
virtual Result GetSize(u64 *out_size) override;
|
virtual Result GetSize(u64 *out_size) override;
|
||||||
virtual Result OperateRange(FsOperationId operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override;
|
virtual Result OperateRange(FsOperationId operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -35,16 +35,14 @@ struct FsMitmManagerOptions {
|
|||||||
};
|
};
|
||||||
using FsMitmManager = WaitableManager<FsMitmManagerOptions>;
|
using FsMitmManager = WaitableManager<FsMitmManagerOptions>;
|
||||||
|
|
||||||
void FsMitmMain(void *arg) {
|
void FsMitmMain(void *arg) {
|
||||||
/* Create server manager. */
|
/* Create server manager. */
|
||||||
auto server_manager = new FsMitmManager(5);
|
static auto s_server_manager = FsMitmManager(5);
|
||||||
|
|
||||||
/* Create fsp-srv mitm. */
|
/* Create fsp-srv mitm. */
|
||||||
AddMitmServerToManager<FsMitmService>(server_manager, "fsp-srv", 61);
|
AddMitmServerToManager<FsMitmService>(&s_server_manager, "fsp-srv", 61);
|
||||||
|
|
||||||
/* Loop forever, servicing our services. */
|
/* Loop forever, servicing our services. */
|
||||||
server_manager->Process();
|
s_server_manager.Process();
|
||||||
|
|
||||||
delete server_manager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
@@ -24,63 +24,67 @@
|
|||||||
|
|
||||||
void RomFSBuildContext::VisitDirectory(FsFileSystem *filesys, RomFSBuildDirectoryContext *parent) {
|
void RomFSBuildContext::VisitDirectory(FsFileSystem *filesys, RomFSBuildDirectoryContext *parent) {
|
||||||
FsDir dir;
|
FsDir dir;
|
||||||
Result rc;
|
|
||||||
|
|
||||||
std::vector<RomFSBuildDirectoryContext *> child_dirs;
|
std::vector<RomFSBuildDirectoryContext *> child_dirs;
|
||||||
|
|
||||||
/* Open the current parent directory. */
|
/* Open the current parent directory. */
|
||||||
if (R_FAILED((rc = Utils::OpenRomFSDir(filesys, this->title_id, parent->path, &dir)))) {
|
R_ASSERT(Utils::OpenRomFSDir(filesys, this->title_id, parent->path, &dir));
|
||||||
fatalSimple(rc);
|
{
|
||||||
}
|
ON_SCOPE_EXIT { fsDirClose(&dir); };
|
||||||
|
|
||||||
u64 read_entries;
|
u64 read_entries;
|
||||||
while (R_SUCCEEDED((rc = fsDirRead(&dir, 0, &read_entries, 1, &this->dir_entry))) && read_entries == 1) {
|
while (true) {
|
||||||
if (this->dir_entry.type == ENTRYTYPE_DIR) {
|
R_ASSERT(fsDirRead(&dir, 0, &read_entries, 1, &this->dir_entry));
|
||||||
RomFSBuildDirectoryContext *child = new RomFSBuildDirectoryContext({0});
|
if (read_entries != 1) {
|
||||||
/* Set child's path. */
|
break;
|
||||||
child->cur_path_ofs = parent->path_len + 1;
|
|
||||||
child->path_len = child->cur_path_ofs + strlen(this->dir_entry.name);
|
|
||||||
child->path = new char[child->path_len + 1];
|
|
||||||
strcpy(child->path, parent->path);
|
|
||||||
if (child->path_len > FS_MAX_PATH - 1) {
|
|
||||||
fatalSimple(ResultFsTooLongPath);
|
|
||||||
}
|
}
|
||||||
strcat(child->path + parent->path_len, "/");
|
|
||||||
strcat(child->path + parent->path_len, this->dir_entry.name);
|
if (this->dir_entry.type == ENTRYTYPE_DIR) {
|
||||||
|
RomFSBuildDirectoryContext *child = new RomFSBuildDirectoryContext({0});
|
||||||
if (!this->AddDirectory(parent, child, NULL)) {
|
/* Set child's path. */
|
||||||
delete[] child->path;
|
child->cur_path_ofs = parent->path_len + 1;
|
||||||
delete child;
|
child->path_len = child->cur_path_ofs + strlen(this->dir_entry.name);
|
||||||
|
child->path = new char[child->path_len + 1];
|
||||||
|
strcpy(child->path, parent->path);
|
||||||
|
if (child->path_len > FS_MAX_PATH - 1) {
|
||||||
|
fatalSimple(ResultFsTooLongPath);
|
||||||
|
}
|
||||||
|
strcat(child->path + parent->path_len, "/");
|
||||||
|
strcat(child->path + parent->path_len, this->dir_entry.name);
|
||||||
|
|
||||||
|
if (!this->AddDirectory(parent, child, NULL)) {
|
||||||
|
delete[] child->path;
|
||||||
|
delete child;
|
||||||
|
} else {
|
||||||
|
child_dirs.push_back(child);
|
||||||
|
}
|
||||||
|
} else if (this->dir_entry.type == ENTRYTYPE_FILE) {
|
||||||
|
RomFSBuildFileContext *child = new RomFSBuildFileContext({0});
|
||||||
|
/* Set child's path. */
|
||||||
|
child->cur_path_ofs = parent->path_len + 1;
|
||||||
|
child->path_len = child->cur_path_ofs + strlen(this->dir_entry.name);
|
||||||
|
child->path = new char[child->path_len + 1];
|
||||||
|
strcpy(child->path, parent->path);
|
||||||
|
if (child->path_len > FS_MAX_PATH - 1) {
|
||||||
|
fatalSimple(ResultFsTooLongPath);
|
||||||
|
}
|
||||||
|
strcat(child->path + parent->path_len, "/");
|
||||||
|
strcat(child->path + parent->path_len, this->dir_entry.name);
|
||||||
|
|
||||||
|
child->source = this->cur_source_type;
|
||||||
|
|
||||||
|
child->size = this->dir_entry.fileSize;
|
||||||
|
|
||||||
|
if (!this->AddFile(parent, child)) {
|
||||||
|
delete[] child->path;
|
||||||
|
delete child;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
child_dirs.push_back(child);
|
std::abort();
|
||||||
}
|
}
|
||||||
} else if (this->dir_entry.type == ENTRYTYPE_FILE) {
|
|
||||||
RomFSBuildFileContext *child = new RomFSBuildFileContext({0});
|
|
||||||
/* Set child's path. */
|
|
||||||
child->cur_path_ofs = parent->path_len + 1;
|
|
||||||
child->path_len = child->cur_path_ofs + strlen(this->dir_entry.name);
|
|
||||||
child->path = new char[child->path_len + 1];
|
|
||||||
strcpy(child->path, parent->path);
|
|
||||||
if (child->path_len > FS_MAX_PATH - 1) {
|
|
||||||
fatalSimple(ResultFsTooLongPath);
|
|
||||||
}
|
|
||||||
strcat(child->path + parent->path_len, "/");
|
|
||||||
strcat(child->path + parent->path_len, this->dir_entry.name);
|
|
||||||
|
|
||||||
child->source = this->cur_source_type;
|
|
||||||
|
|
||||||
child->size = this->dir_entry.fileSize;
|
|
||||||
|
|
||||||
if (!this->AddFile(parent, child)) {
|
|
||||||
delete[] child->path;
|
|
||||||
delete child;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fsDirClose(&dir);
|
|
||||||
|
|
||||||
for (auto &child : child_dirs) {
|
for (auto &child : child_dirs) {
|
||||||
this->VisitDirectory(filesys, child);
|
this->VisitDirectory(filesys, child);
|
||||||
}
|
}
|
||||||
@@ -121,7 +125,7 @@ void RomFSBuildContext::VisitDirectory(RomFSBuildDirectoryContext *parent, u32 p
|
|||||||
strcat(child->path + parent->path_len, "/");
|
strcat(child->path + parent->path_len, "/");
|
||||||
strncat(child->path + parent->path_len, cur_file->name, cur_file->name_size);
|
strncat(child->path + parent->path_len, cur_file->name, cur_file->name_size);
|
||||||
child->size = cur_file->size;
|
child->size = cur_file->size;
|
||||||
|
|
||||||
child->source = this->cur_source_type;
|
child->source = this->cur_source_type;
|
||||||
child->orig_offset = cur_file->offset;
|
child->orig_offset = cur_file->offset;
|
||||||
if (!this->AddFile(parent, child)) {
|
if (!this->AddFile(parent, child)) {
|
||||||
@@ -150,7 +154,7 @@ void RomFSBuildContext::VisitDirectory(RomFSBuildDirectoryContext *parent, u32 p
|
|||||||
}
|
}
|
||||||
strcat(child->path + parent->path_len, "/");
|
strcat(child->path + parent->path_len, "/");
|
||||||
strncat(child->path + parent->path_len, cur_child->name, cur_child->name_size);
|
strncat(child->path + parent->path_len, cur_child->name, cur_child->name_size);
|
||||||
|
|
||||||
RomFSBuildDirectoryContext *real = NULL;
|
RomFSBuildDirectoryContext *real = NULL;
|
||||||
if (!this->AddDirectory(parent, child, &real)) {
|
if (!this->AddDirectory(parent, child, &real)) {
|
||||||
delete[] child->path;
|
delete[] child->path;
|
||||||
@@ -160,9 +164,9 @@ void RomFSBuildContext::VisitDirectory(RomFSBuildDirectoryContext *parent, u32 p
|
|||||||
/* TODO: Better error. */
|
/* TODO: Better error. */
|
||||||
fatalSimple(ResultKernelConnectionClosed);
|
fatalSimple(ResultKernelConnectionClosed);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->VisitDirectory(real, cur_child_offset, dir_table, dir_table_size, file_table, file_table_size);
|
this->VisitDirectory(real, cur_child_offset, dir_table, dir_table_size, file_table, file_table_size);
|
||||||
|
|
||||||
if (cur_child->sibling == ROMFS_ENTRY_EMPTY) {
|
if (cur_child->sibling == ROMFS_ENTRY_EMPTY) {
|
||||||
cur_child = NULL;
|
cur_child = NULL;
|
||||||
} else {
|
} else {
|
||||||
@@ -174,26 +178,19 @@ void RomFSBuildContext::VisitDirectory(RomFSBuildDirectoryContext *parent, u32 p
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RomFSBuildContext::MergeRomStorage(IROStorage *storage, RomFSDataSource source) {
|
void RomFSBuildContext::MergeRomStorage(IROStorage *storage, RomFSDataSource source) {
|
||||||
Result rc;
|
|
||||||
RomFSHeader header;
|
RomFSHeader header;
|
||||||
if (R_FAILED((rc = storage->Read(&header, sizeof(header), 0)))) {
|
R_ASSERT(storage->Read(&header, sizeof(header), 0));
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
if (header.header_size != sizeof(header)) {
|
if (header.header_size != sizeof(header)) {
|
||||||
/* what */
|
/* what */
|
||||||
return;
|
std::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read tables. */
|
/* Read tables. */
|
||||||
auto dir_table = std::make_unique<u8[]>(header.dir_table_size);
|
auto dir_table = std::make_unique<u8[]>(header.dir_table_size);
|
||||||
auto file_table = std::make_unique<u8[]>(header.file_table_size);
|
auto file_table = std::make_unique<u8[]>(header.file_table_size);
|
||||||
if (R_FAILED((rc = storage->Read(dir_table.get(), header.dir_table_size, header.dir_table_ofs)))) {
|
R_ASSERT(storage->Read(dir_table.get(), header.dir_table_size, header.dir_table_ofs));
|
||||||
fatalSimple(rc);
|
R_ASSERT(storage->Read(file_table.get(), header.file_table_size, header.file_table_ofs));
|
||||||
}
|
|
||||||
if (R_FAILED((rc = storage->Read(file_table.get(), header.file_table_size, header.file_table_ofs)))) {
|
|
||||||
fatalSimple(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->cur_source_type = source;
|
this->cur_source_type = source;
|
||||||
this->VisitDirectory(this->root, 0x0, dir_table.get(), (size_t)header.dir_table_size, file_table.get(), (size_t)header.file_table_size);
|
this->VisitDirectory(this->root, 0x0, dir_table.get(), (size_t)header.dir_table_size, file_table.get(), (size_t)header.file_table_size);
|
||||||
}
|
}
|
||||||
@@ -207,13 +204,13 @@ bool RomFSBuildContext::AddDirectory(RomFSBuildDirectoryContext *parent_dir_ctx,
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a new directory. */
|
/* Add a new directory. */
|
||||||
this->num_dirs++;
|
this->num_dirs++;
|
||||||
this->dir_table_size += sizeof(RomFSDirectoryEntry) + ((dir_ctx->path_len - dir_ctx->cur_path_ofs + 3) & ~3);
|
this->dir_table_size += sizeof(RomFSDirectoryEntry) + ((dir_ctx->path_len - dir_ctx->cur_path_ofs + 3) & ~3);
|
||||||
dir_ctx->parent = parent_dir_ctx;
|
dir_ctx->parent = parent_dir_ctx;
|
||||||
this->directories.insert({dir_ctx->path, dir_ctx});
|
this->directories.insert({dir_ctx->path, dir_ctx});
|
||||||
|
|
||||||
if (out_dir_ctx) {
|
if (out_dir_ctx) {
|
||||||
*out_dir_ctx = dir_ctx;
|
*out_dir_ctx = dir_ctx;
|
||||||
}
|
}
|
||||||
@@ -226,13 +223,13 @@ bool RomFSBuildContext::AddFile(RomFSBuildDirectoryContext *parent_dir_ctx, RomF
|
|||||||
if (existing != this->files.end()) {
|
if (existing != this->files.end()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a new file. */
|
/* Add a new file. */
|
||||||
this->num_files++;
|
this->num_files++;
|
||||||
this->file_table_size += sizeof(RomFSFileEntry) + ((file_ctx->path_len - file_ctx->cur_path_ofs + 3) & ~3);
|
this->file_table_size += sizeof(RomFSFileEntry) + ((file_ctx->path_len - file_ctx->cur_path_ofs + 3) & ~3);
|
||||||
file_ctx->parent = parent_dir_ctx;
|
file_ctx->parent = parent_dir_ctx;
|
||||||
this->files.insert({file_ctx->path, file_ctx});
|
this->files.insert({file_ctx->path, file_ctx});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,12 +237,12 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) {
|
|||||||
RomFSBuildFileContext *cur_file;
|
RomFSBuildFileContext *cur_file;
|
||||||
RomFSBuildDirectoryContext *cur_dir;
|
RomFSBuildDirectoryContext *cur_dir;
|
||||||
u32 entry_offset;
|
u32 entry_offset;
|
||||||
|
|
||||||
u32 dir_hash_table_entry_count = romfs_get_hash_table_count(this->num_dirs);
|
u32 dir_hash_table_entry_count = romfs_get_hash_table_count(this->num_dirs);
|
||||||
u32 file_hash_table_entry_count = romfs_get_hash_table_count(this->num_files);
|
u32 file_hash_table_entry_count = romfs_get_hash_table_count(this->num_files);
|
||||||
this->dir_hash_table_size = 4 * dir_hash_table_entry_count;
|
this->dir_hash_table_size = 4 * dir_hash_table_entry_count;
|
||||||
this->file_hash_table_size = 4 * file_hash_table_entry_count;
|
this->file_hash_table_size = 4 * file_hash_table_entry_count;
|
||||||
|
|
||||||
/* Assign metadata pointers */
|
/* Assign metadata pointers */
|
||||||
auto *header = reinterpret_cast<RomFSHeader*>(std::malloc(sizeof(RomFSHeader)));
|
auto *header = reinterpret_cast<RomFSHeader*>(std::malloc(sizeof(RomFSHeader)));
|
||||||
*header = {};
|
*header = {};
|
||||||
@@ -255,7 +252,7 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) {
|
|||||||
RomFSDirectoryEntry *dir_table = (RomFSDirectoryEntry *)((uintptr_t)dir_hash_table + this->dir_hash_table_size);
|
RomFSDirectoryEntry *dir_table = (RomFSDirectoryEntry *)((uintptr_t)dir_hash_table + this->dir_hash_table_size);
|
||||||
u32 *file_hash_table = (u32 *)((uintptr_t)dir_table + this->dir_table_size);
|
u32 *file_hash_table = (u32 *)((uintptr_t)dir_table + this->dir_table_size);
|
||||||
RomFSFileEntry *file_table = (RomFSFileEntry *)((uintptr_t)file_hash_table + this->file_hash_table_size);
|
RomFSFileEntry *file_table = (RomFSFileEntry *)((uintptr_t)file_hash_table + this->file_hash_table_size);
|
||||||
|
|
||||||
/* Clear out hash tables. */
|
/* Clear out hash tables. */
|
||||||
for (u32 i = 0; i < dir_hash_table_entry_count; i++) {
|
for (u32 i = 0; i < dir_hash_table_entry_count; i++) {
|
||||||
dir_hash_table[i] = ROMFS_ENTRY_EMPTY;
|
dir_hash_table[i] = ROMFS_ENTRY_EMPTY;
|
||||||
@@ -263,10 +260,10 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) {
|
|||||||
for (u32 i = 0; i < file_hash_table_entry_count; i++) {
|
for (u32 i = 0; i < file_hash_table_entry_count; i++) {
|
||||||
file_hash_table[i] = ROMFS_ENTRY_EMPTY;
|
file_hash_table[i] = ROMFS_ENTRY_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_infos->clear();
|
out_infos->clear();
|
||||||
out_infos->emplace_back(0, sizeof(*header), header, RomFSDataSource::Memory);
|
out_infos->emplace_back(0, sizeof(*header), header, RomFSDataSource::Memory);
|
||||||
|
|
||||||
/* Determine file offsets. */
|
/* Determine file offsets. */
|
||||||
entry_offset = 0;
|
entry_offset = 0;
|
||||||
RomFSBuildFileContext *prev_file = NULL;
|
RomFSBuildFileContext *prev_file = NULL;
|
||||||
@@ -297,7 +294,7 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) {
|
|||||||
cur_file->sibling = cur_file->parent->file;
|
cur_file->sibling = cur_file->parent->file;
|
||||||
cur_file->parent->file = cur_file;
|
cur_file->parent->file = cur_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine directory offsets. */
|
/* Determine directory offsets. */
|
||||||
entry_offset = 0;
|
entry_offset = 0;
|
||||||
for (const auto &it : this->directories) {
|
for (const auto &it : this->directories) {
|
||||||
@@ -311,8 +308,8 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) {
|
|||||||
cur_dir->sibling = cur_dir->parent->child;
|
cur_dir->sibling = cur_dir->parent->child;
|
||||||
cur_dir->parent->child = cur_dir;
|
cur_dir->parent->child = cur_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Populate file tables. */
|
/* Populate file tables. */
|
||||||
for (const auto &it : this->files) {
|
for (const auto &it : this->files) {
|
||||||
cur_file = it.second;
|
cur_file = it.second;
|
||||||
@@ -322,16 +319,16 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) {
|
|||||||
cur_entry->sibling = (cur_file->sibling == NULL) ? ROMFS_ENTRY_EMPTY : cur_file->sibling->entry_offset;
|
cur_entry->sibling = (cur_file->sibling == NULL) ? ROMFS_ENTRY_EMPTY : cur_file->sibling->entry_offset;
|
||||||
cur_entry->offset = cur_file->offset;
|
cur_entry->offset = cur_file->offset;
|
||||||
cur_entry->size = cur_file->size;
|
cur_entry->size = cur_file->size;
|
||||||
|
|
||||||
u32 name_size = cur_file->path_len - cur_file->cur_path_ofs;
|
u32 name_size = cur_file->path_len - cur_file->cur_path_ofs;
|
||||||
u32 hash = romfs_calc_path_hash(cur_file->parent->entry_offset, (unsigned char *)cur_file->path + cur_file->cur_path_ofs, 0, name_size);
|
u32 hash = romfs_calc_path_hash(cur_file->parent->entry_offset, (unsigned char *)cur_file->path + cur_file->cur_path_ofs, 0, name_size);
|
||||||
cur_entry->hash = file_hash_table[hash % file_hash_table_entry_count];
|
cur_entry->hash = file_hash_table[hash % file_hash_table_entry_count];
|
||||||
file_hash_table[hash % file_hash_table_entry_count] = cur_file->entry_offset;
|
file_hash_table[hash % file_hash_table_entry_count] = cur_file->entry_offset;
|
||||||
|
|
||||||
cur_entry->name_size = name_size;
|
cur_entry->name_size = name_size;
|
||||||
memset(cur_entry->name, 0, (cur_entry->name_size + 3) & ~3);
|
memset(cur_entry->name, 0, (cur_entry->name_size + 3) & ~3);
|
||||||
memcpy(cur_entry->name, cur_file->path + cur_file->cur_path_ofs, name_size);
|
memcpy(cur_entry->name, cur_file->path + cur_file->cur_path_ofs, name_size);
|
||||||
|
|
||||||
switch (cur_file->source) {
|
switch (cur_file->source) {
|
||||||
case RomFSDataSource::BaseRomFS:
|
case RomFSDataSource::BaseRomFS:
|
||||||
case RomFSDataSource::FileRomFS:
|
case RomFSDataSource::FileRomFS:
|
||||||
@@ -355,7 +352,7 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Populate dir tables. */
|
/* Populate dir tables. */
|
||||||
for (const auto &it : this->directories) {
|
for (const auto &it : this->directories) {
|
||||||
cur_dir = it.second;
|
cur_dir = it.second;
|
||||||
@@ -364,17 +361,17 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) {
|
|||||||
cur_entry->sibling = (cur_dir->sibling == NULL) ? ROMFS_ENTRY_EMPTY : cur_dir->sibling->entry_offset;
|
cur_entry->sibling = (cur_dir->sibling == NULL) ? ROMFS_ENTRY_EMPTY : cur_dir->sibling->entry_offset;
|
||||||
cur_entry->child = (cur_dir->child == NULL) ? ROMFS_ENTRY_EMPTY : cur_dir->child->entry_offset;
|
cur_entry->child = (cur_dir->child == NULL) ? ROMFS_ENTRY_EMPTY : cur_dir->child->entry_offset;
|
||||||
cur_entry->file = (cur_dir->file == NULL) ? ROMFS_ENTRY_EMPTY : cur_dir->file->entry_offset;
|
cur_entry->file = (cur_dir->file == NULL) ? ROMFS_ENTRY_EMPTY : cur_dir->file->entry_offset;
|
||||||
|
|
||||||
u32 name_size = cur_dir->path_len - cur_dir->cur_path_ofs;
|
u32 name_size = cur_dir->path_len - cur_dir->cur_path_ofs;
|
||||||
u32 hash = romfs_calc_path_hash(cur_dir == this->root ? 0 : cur_dir->parent->entry_offset, (unsigned char *)cur_dir->path + cur_dir->cur_path_ofs, 0, name_size);
|
u32 hash = romfs_calc_path_hash(cur_dir == this->root ? 0 : cur_dir->parent->entry_offset, (unsigned char *)cur_dir->path + cur_dir->cur_path_ofs, 0, name_size);
|
||||||
cur_entry->hash = dir_hash_table[hash % dir_hash_table_entry_count];
|
cur_entry->hash = dir_hash_table[hash % dir_hash_table_entry_count];
|
||||||
dir_hash_table[hash % dir_hash_table_entry_count] = cur_dir->entry_offset;
|
dir_hash_table[hash % dir_hash_table_entry_count] = cur_dir->entry_offset;
|
||||||
|
|
||||||
cur_entry->name_size = name_size;
|
cur_entry->name_size = name_size;
|
||||||
memset(cur_entry->name, 0, (cur_entry->name_size + 3) & ~3);
|
memset(cur_entry->name, 0, (cur_entry->name_size + 3) & ~3);
|
||||||
memcpy(cur_entry->name, cur_dir->path + cur_dir->cur_path_ofs, name_size);
|
memcpy(cur_entry->name, cur_dir->path + cur_dir->cur_path_ofs, name_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete directories. */
|
/* Delete directories. */
|
||||||
for (const auto &it : this->directories) {
|
for (const auto &it : this->directories) {
|
||||||
cur_dir = it.second;
|
cur_dir = it.second;
|
||||||
@@ -383,7 +380,7 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) {
|
|||||||
}
|
}
|
||||||
this->root = NULL;
|
this->root = NULL;
|
||||||
this->directories.clear();
|
this->directories.clear();
|
||||||
|
|
||||||
/* Delete files. */
|
/* Delete files. */
|
||||||
for (const auto &it : this->files) {
|
for (const auto &it : this->files) {
|
||||||
cur_file = it.second;
|
cur_file = it.second;
|
||||||
@@ -391,7 +388,7 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) {
|
|||||||
delete cur_file;
|
delete cur_file;
|
||||||
}
|
}
|
||||||
this->files.clear();
|
this->files.clear();
|
||||||
|
|
||||||
/* Set header fields. */
|
/* Set header fields. */
|
||||||
header->header_size = sizeof(*header);
|
header->header_size = sizeof(*header);
|
||||||
header->file_hash_table_size = this->file_hash_table_size;
|
header->file_hash_table_size = this->file_hash_table_size;
|
||||||
@@ -411,5 +408,5 @@ void RomFSBuildContext::Build(std::vector<RomFSSourceInfo> *out_infos) {
|
|||||||
} else {
|
} else {
|
||||||
out_infos->emplace_back(header->dir_hash_table_ofs, metadata_size, metadata, RomFSDataSource::Memory);
|
out_infos->emplace_back(header->dir_hash_table_ofs, metadata_size, metadata, RomFSDataSource::Memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
@@ -67,7 +67,7 @@ struct RomFSSourceInfo {
|
|||||||
RomFSMetaDataSourceInfo metadata_source_info;
|
RomFSMetaDataSourceInfo metadata_source_info;
|
||||||
};
|
};
|
||||||
RomFSDataSource type;
|
RomFSDataSource type;
|
||||||
|
|
||||||
RomFSSourceInfo(u64 v_o, u64 s, u64 offset, RomFSDataSource t) : virtual_offset(v_o), size(s), type(t) {
|
RomFSSourceInfo(u64 v_o, u64 s, u64 offset, RomFSDataSource t) : virtual_offset(v_o), size(s), type(t) {
|
||||||
switch (this->type) {
|
switch (this->type) {
|
||||||
case RomFSDataSource::BaseRomFS:
|
case RomFSDataSource::BaseRomFS:
|
||||||
@@ -85,7 +85,7 @@ struct RomFSSourceInfo {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RomFSSourceInfo(u64 v_o, u64 s, const void *arg, RomFSDataSource t) : virtual_offset(v_o), size(s), type(t) {
|
RomFSSourceInfo(u64 v_o, u64 s, const void *arg, RomFSDataSource t) : virtual_offset(v_o), size(s), type(t) {
|
||||||
switch (this->type) {
|
switch (this->type) {
|
||||||
case RomFSDataSource::LooseFile:
|
case RomFSDataSource::LooseFile:
|
||||||
@@ -103,7 +103,7 @@ struct RomFSSourceInfo {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RomFSSourceInfo(u64 v_o, u64 s, RomFSDataSource t) : virtual_offset(v_o), size(s), type(t) {
|
RomFSSourceInfo(u64 v_o, u64 s, RomFSDataSource t) : virtual_offset(v_o), size(s), type(t) {
|
||||||
switch (this->type) {
|
switch (this->type) {
|
||||||
case RomFSDataSource::MetaData:
|
case RomFSDataSource::MetaData:
|
||||||
@@ -118,7 +118,7 @@ struct RomFSSourceInfo {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cleanup() {
|
void Cleanup() {
|
||||||
switch (this->type) {
|
switch (this->type) {
|
||||||
case RomFSDataSource::BaseRomFS:
|
case RomFSDataSource::BaseRomFS:
|
||||||
@@ -137,7 +137,7 @@ struct RomFSSourceInfo {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Compare(RomFSSourceInfo *a, RomFSSourceInfo *b) {
|
static bool Compare(RomFSSourceInfo *a, RomFSSourceInfo *b) {
|
||||||
return (a->virtual_offset < b->virtual_offset);
|
return (a->virtual_offset < b->virtual_offset);
|
||||||
}
|
}
|
||||||
@@ -229,13 +229,13 @@ class RomFSBuildContext {
|
|||||||
u64 dir_hash_table_size = 0;
|
u64 dir_hash_table_size = 0;
|
||||||
u64 file_hash_table_size = 0;
|
u64 file_hash_table_size = 0;
|
||||||
u64 file_partition_size = 0;
|
u64 file_partition_size = 0;
|
||||||
|
|
||||||
FsDirectoryEntry dir_entry;
|
FsDirectoryEntry dir_entry;
|
||||||
RomFSDataSource cur_source_type;
|
RomFSDataSource cur_source_type;
|
||||||
|
|
||||||
void VisitDirectory(FsFileSystem *filesys, RomFSBuildDirectoryContext *parent);
|
void VisitDirectory(FsFileSystem *filesys, RomFSBuildDirectoryContext *parent);
|
||||||
void VisitDirectory(RomFSBuildDirectoryContext *parent, u32 parent_offset, void *dir_table, size_t dir_table_size, void *file_table, size_t file_table_size);
|
void VisitDirectory(RomFSBuildDirectoryContext *parent, u32 parent_offset, void *dir_table, size_t dir_table_size, void *file_table, size_t file_table_size);
|
||||||
|
|
||||||
bool AddDirectory(RomFSBuildDirectoryContext *parent_dir_ctx, RomFSBuildDirectoryContext *dir_ctx, RomFSBuildDirectoryContext **out_dir_ctx);
|
bool AddDirectory(RomFSBuildDirectoryContext *parent_dir_ctx, RomFSBuildDirectoryContext *dir_ctx, RomFSBuildDirectoryContext **out_dir_ctx);
|
||||||
bool AddFile(RomFSBuildDirectoryContext *parent_dir_ctx, RomFSBuildFileContext *file_ctx);
|
bool AddFile(RomFSBuildDirectoryContext *parent_dir_ctx, RomFSBuildFileContext *file_ctx);
|
||||||
public:
|
public:
|
||||||
@@ -247,10 +247,10 @@ class RomFSBuildContext {
|
|||||||
this->num_dirs = 1;
|
this->num_dirs = 1;
|
||||||
this->dir_table_size = 0x18;
|
this->dir_table_size = 0x18;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MergeSdFiles();
|
void MergeSdFiles();
|
||||||
void MergeRomStorage(IROStorage *storage, RomFSDataSource source);
|
void MergeRomStorage(IROStorage *storage, RomFSDataSource source);
|
||||||
|
|
||||||
/* This finalizes the context. */
|
/* This finalizes the context. */
|
||||||
void Build(std::vector<RomFSSourceInfo> *out_infos);
|
void Build(std::vector<RomFSSourceInfo> *out_infos);
|
||||||
};
|
};
|
||||||
@@ -270,7 +270,7 @@ static inline uint32_t romfs_calc_path_hash(uint32_t parent, const unsigned char
|
|||||||
hash = (hash >> 5) | (hash << 27);
|
hash = (hash >> 5) | (hash << 27);
|
||||||
hash ^= path[start + i];
|
hash ^= path[start + i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
@@ -38,11 +38,11 @@ class RomFileStorage : public IROStorage {
|
|||||||
public:
|
public:
|
||||||
Result Read(void *buffer, size_t size, u64 offset) override {
|
Result Read(void *buffer, size_t size, u64 offset) override {
|
||||||
size_t out_sz = 0;
|
size_t out_sz = 0;
|
||||||
Result rc = fsFileRead(this->base_file, offset, buffer, size, FS_READOPTION_NONE, &out_sz);
|
R_TRY(fsFileRead(this->base_file, offset, buffer, size, FS_READOPTION_NONE, &out_sz));
|
||||||
if (R_SUCCEEDED(rc) && out_sz != size && out_sz) {
|
if (out_sz != size && out_sz) {
|
||||||
return this->Read((void *)((uintptr_t)buffer + out_sz), size - out_sz, offset + out_sz);
|
R_TRY(this->Read((void *)((uintptr_t)buffer + out_sz), size - out_sz, offset + out_sz));
|
||||||
}
|
}
|
||||||
return rc;
|
return ResultSuccess;
|
||||||
};
|
};
|
||||||
Result GetSize(u64 *out_size) override {
|
Result GetSize(u64 *out_size) override {
|
||||||
return fsFileGetSize(this->base_file, out_size);
|
return fsFileGetSize(this->base_file, out_size);
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ static void StorageCacheSetEntry(u64 title_id, std::shared_ptr<IStorageInterface
|
|||||||
|
|
||||||
void FsMitmService::PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx) {
|
void FsMitmService::PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx) {
|
||||||
auto this_ptr = static_cast<FsMitmService *>(obj);
|
auto this_ptr = static_cast<FsMitmService *>(obj);
|
||||||
switch ((FspSrvCmd)ctx->cmd_id) {
|
switch (static_cast<CommandId>(ctx->cmd_id)) {
|
||||||
case FspSrvCmd_SetCurrentProcess:
|
case CommandId::SetCurrentProcess:
|
||||||
if (R_SUCCEEDED(ctx->rc)) {
|
if (R_SUCCEEDED(ctx->rc)) {
|
||||||
this_ptr->has_initialized = true;
|
this_ptr->has_initialized = true;
|
||||||
this_ptr->process_id = ctx->request.Pid;
|
this_ptr->process_id = ctx->request.Pid;
|
||||||
@@ -87,31 +87,18 @@ void FsMitmService::PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result FsMitmService::OpenHblWebContentFileSystem(Out<std::shared_ptr<IFileSystemInterface>> &out_fs) {
|
Result FsMitmService::OpenHblWebContentFileSystem(Out<std::shared_ptr<IFileSystemInterface>> &out_fs) {
|
||||||
std::shared_ptr<IFileSystemInterface> fs = nullptr;
|
|
||||||
u32 out_domain_id = 0;
|
|
||||||
Result rc = ResultSuccess;
|
|
||||||
|
|
||||||
ON_SCOPE_EXIT {
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
out_fs.SetValue(std::move(fs));
|
|
||||||
if (out_fs.IsDomain()) {
|
|
||||||
out_fs.ChangeObjectId(out_domain_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Mount the SD card using fs.mitm's session. */
|
/* Mount the SD card using fs.mitm's session. */
|
||||||
FsFileSystem sd_fs;
|
FsFileSystem sd_fs;
|
||||||
rc = fsMountSdcard(&sd_fs);
|
R_TRY(fsMountSdcard(&sd_fs));
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
std::unique_ptr<IFileSystem> web_ifs = std::make_unique<SubDirectoryFileSystem>(std::make_shared<ProxyFileSystem>(sd_fs), AtmosphereHblWebContentDir);
|
/* Set output filesystem. */
|
||||||
fs = std::make_shared<IFileSystemInterface>(std::move(web_ifs));
|
std::unique_ptr<IFileSystem> web_ifs = std::make_unique<SubDirectoryFileSystem>(std::make_shared<ProxyFileSystem>(sd_fs), AtmosphereHblWebContentDir);
|
||||||
if (out_fs.IsDomain()) {
|
out_fs.SetValue(std::make_shared<IFileSystemInterface>(std::move(web_ifs)));
|
||||||
out_domain_id = sd_fs.s.object_id;
|
if (out_fs.IsDomain()) {
|
||||||
}
|
out_fs.ChangeObjectId(sd_fs.s.object_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FsMitmService::OpenFileSystemWithPatch(Out<std::shared_ptr<IFileSystemInterface>> out_fs, u64 title_id, u32 filesystem_type) {
|
Result FsMitmService::OpenFileSystemWithPatch(Out<std::shared_ptr<IFileSystemInterface>> out_fs, u64 title_id, u32 filesystem_type) {
|
||||||
@@ -171,32 +158,18 @@ Result FsMitmService::OpenSdCardFileSystem(Out<std::shared_ptr<IFileSystemInterf
|
|||||||
return ResultAtmosphereMitmShouldForwardToSession;
|
return ResultAtmosphereMitmShouldForwardToSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<IFileSystemInterface> fs = nullptr;
|
|
||||||
u32 out_domain_id = 0;
|
|
||||||
Result rc = ResultSuccess;
|
|
||||||
|
|
||||||
ON_SCOPE_EXIT {
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
out_fs.SetValue(std::move(fs));
|
|
||||||
if (out_fs.IsDomain()) {
|
|
||||||
out_fs.ChangeObjectId(out_domain_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Mount the SD card. */
|
/* Mount the SD card. */
|
||||||
FsFileSystem sd_fs;
|
FsFileSystem sd_fs;
|
||||||
if (R_FAILED((rc = fsMountSdcard(&sd_fs)))) {
|
R_TRY(fsMountSdcard(&sd_fs));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<IFileSystem> redir_fs = std::make_shared<DirectoryRedirectionFileSystem>(new ProxyFileSystem(sd_fs), "/Nintendo", GetEmummcNintendoDirPath());
|
/* Set output filesystem. */
|
||||||
fs = std::make_shared<IFileSystemInterface>(redir_fs);
|
std::unique_ptr<IFileSystem> redir_fs = std::make_unique<DirectoryRedirectionFileSystem>(new ProxyFileSystem(sd_fs), "/Nintendo", GetEmummcNintendoDirPath());
|
||||||
|
out_fs.SetValue(std::make_shared<IFileSystemInterface>(std::move(redir_fs)));
|
||||||
if (out_fs.IsDomain()) {
|
if (out_fs.IsDomain()) {
|
||||||
out_domain_id = sd_fs.s.object_id;
|
out_fs.ChangeObjectId(sd_fs.s.object_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FsMitmService::OpenSaveDataFileSystem(Out<std::shared_ptr<IFileSystemInterface>> out_fs, u8 space_id, FsSave save_struct) {
|
Result FsMitmService::OpenSaveDataFileSystem(Out<std::shared_ptr<IFileSystemInterface>> out_fs, u8 space_id, FsSave save_struct) {
|
||||||
@@ -219,33 +192,16 @@ Result FsMitmService::OpenSaveDataFileSystem(Out<std::shared_ptr<IFileSystemInte
|
|||||||
std::unique_ptr<IFileSystem> save_ifs = std::make_unique<ProxyFileSystem>(save_fs);
|
std::unique_ptr<IFileSystem> save_ifs = std::make_unique<ProxyFileSystem>(save_fs);
|
||||||
|
|
||||||
{
|
{
|
||||||
std::shared_ptr<IFileSystemInterface> fs = nullptr;
|
|
||||||
u32 out_domain_id = 0;
|
|
||||||
Result rc = ResultSuccess;
|
|
||||||
|
|
||||||
ON_SCOPE_EXIT {
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
out_fs.SetValue(std::move(fs));
|
|
||||||
if (out_fs.IsDomain()) {
|
|
||||||
out_fs.ChangeObjectId(out_domain_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Mount the SD card using fs.mitm's session. */
|
/* Mount the SD card using fs.mitm's session. */
|
||||||
FsFileSystem sd_fs;
|
FsFileSystem sd_fs;
|
||||||
if (R_FAILED((rc = fsMountSdcard(&sd_fs)))) {
|
R_TRY(fsMountSdcard(&sd_fs));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
std::shared_ptr<IFileSystem> sd_ifs = std::make_shared<ProxyFileSystem>(sd_fs);
|
std::shared_ptr<IFileSystem> sd_ifs = std::make_shared<ProxyFileSystem>(sd_fs);
|
||||||
|
|
||||||
|
|
||||||
/* Verify that we can open the save directory, and that it exists. */
|
/* Verify that we can open the save directory, and that it exists. */
|
||||||
const u64 target_tid = save_struct.titleID == 0 ? this->title_id : save_struct.titleID;
|
const u64 target_tid = save_struct.titleID == 0 ? this->title_id : save_struct.titleID;
|
||||||
FsPath save_dir_path;
|
FsPath save_dir_path;
|
||||||
if (R_FAILED((rc = FsSaveUtils::GetSaveDataDirectoryPath(save_dir_path, space_id, save_struct.SaveDataType, target_tid, save_struct.userID, save_struct.saveID)))) {
|
R_TRY(FsSaveUtils::GetSaveDataDirectoryPath(save_dir_path, space_id, save_struct.SaveDataType, target_tid, save_struct.userID, save_struct.saveID));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if this is the first time we're making the save. */
|
/* Check if this is the first time we're making the save. */
|
||||||
bool is_new_save = false;
|
bool is_new_save = false;
|
||||||
@@ -257,9 +213,7 @@ Result FsMitmService::OpenSaveDataFileSystem(Out<std::shared_ptr<IFileSystemInte
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure the directory exists. */
|
/* Ensure the directory exists. */
|
||||||
if (R_FAILED((rc = FsDirUtils::EnsureDirectoryExists(sd_ifs.get(), save_dir_path)))) {
|
R_TRY(FsDirUtils::EnsureDirectoryExists(sd_ifs.get(), save_dir_path));
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<DirectorySaveDataFileSystem> dirsave_ifs = std::make_shared<DirectorySaveDataFileSystem>(new SubDirectoryFileSystem(sd_ifs, save_dir_path.str), std::move(save_ifs));
|
std::shared_ptr<DirectorySaveDataFileSystem> dirsave_ifs = std::make_shared<DirectorySaveDataFileSystem>(new SubDirectoryFileSystem(sd_ifs, save_dir_path.str), std::move(save_ifs));
|
||||||
|
|
||||||
@@ -269,206 +223,170 @@ Result FsMitmService::OpenSaveDataFileSystem(Out<std::shared_ptr<IFileSystemInte
|
|||||||
dirsave_ifs->CopySaveFromProxy();
|
dirsave_ifs->CopySaveFromProxy();
|
||||||
}
|
}
|
||||||
|
|
||||||
fs = std::make_shared<IFileSystemInterface>(static_cast<std::shared_ptr<IFileSystem>>(dirsave_ifs));
|
out_fs.SetValue(std::make_shared<IFileSystemInterface>(static_cast<std::shared_ptr<IFileSystem>>(dirsave_ifs)));
|
||||||
if (out_fs.IsDomain()) {
|
if (out_fs.IsDomain()) {
|
||||||
out_domain_id = sd_fs.s.object_id;
|
out_fs.ChangeObjectId(sd_fs.s.object_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gate access to the BIS partitions. */
|
/* Gate access to the BIS partitions. */
|
||||||
Result FsMitmService::OpenBisStorage(Out<std::shared_ptr<IStorageInterface>> out_storage, u32 _bis_partition_id) {
|
Result FsMitmService::OpenBisStorage(Out<std::shared_ptr<IStorageInterface>> out_storage, u32 _bis_partition_id) {
|
||||||
std::shared_ptr<IStorageInterface> storage = nullptr;
|
|
||||||
u32 out_domain_id = 0;
|
|
||||||
Result rc = ResultSuccess;
|
|
||||||
const FsBisStorageId bis_partition_id = static_cast<FsBisStorageId>(_bis_partition_id);
|
const FsBisStorageId bis_partition_id = static_cast<FsBisStorageId>(_bis_partition_id);
|
||||||
|
|
||||||
ON_SCOPE_EXIT {
|
/* Try to open a storage for the partition. */
|
||||||
if (R_SUCCEEDED(rc)) {
|
FsStorage bis_storage;
|
||||||
out_storage.SetValue(std::move(storage));
|
R_TRY(fsOpenBisStorageFwd(this->forward_service.get(), &bis_storage, bis_partition_id));
|
||||||
if (out_storage.IsDomain()) {
|
|
||||||
out_storage.ChangeObjectId(out_domain_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
const bool is_sysmodule = TitleIdIsSystem(this->title_id);
|
||||||
FsStorage bis_storage;
|
const bool has_bis_write_flag = Utils::HasFlag(this->title_id, "bis_write");
|
||||||
rc = fsOpenBisStorageFwd(this->forward_service.get(), &bis_storage, bis_partition_id);
|
const bool has_cal0_read_flag = Utils::HasFlag(this->title_id, "cal_read");
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
const bool is_sysmodule = TitleIdIsSystem(this->title_id);
|
/* Set output storage. */
|
||||||
const bool has_bis_write_flag = Utils::HasFlag(this->title_id, "bis_write");
|
if (bis_partition_id == FsBisStorageId_Boot0) {
|
||||||
const bool has_cal0_read_flag = Utils::HasFlag(this->title_id, "cal_read");
|
out_storage.SetValue(std::make_shared<IStorageInterface>(new Boot0Storage(bis_storage, this->title_id)));
|
||||||
if (bis_partition_id == FsBisStorageId_Boot0) {
|
} else if (bis_partition_id == FsBisStorageId_CalibrationBinary) {
|
||||||
storage = std::make_shared<IStorageInterface>(new Boot0Storage(bis_storage, this->title_id));
|
/* PRODINFO should *never* be writable. */
|
||||||
} else if (bis_partition_id == FsBisStorageId_CalibrationBinary) {
|
if (is_sysmodule || has_cal0_read_flag) {
|
||||||
/* PRODINFO should *never* be writable. */
|
out_storage.SetValue(std::make_shared<IStorageInterface>(new ReadOnlyStorageAdapter(new ProxyStorage(bis_storage))));
|
||||||
if (is_sysmodule || has_cal0_read_flag) {
|
} else {
|
||||||
storage = std::make_shared<IStorageInterface>(new ReadOnlyStorageAdapter(new ProxyStorage(bis_storage)));
|
/* Do not allow non-sysmodules to read *or* write CAL0. */
|
||||||
} else {
|
fsStorageClose(&bis_storage);
|
||||||
/* Do not allow non-sysmodules to read *or* write CAL0. */
|
return ResultFsPermissionDenied;
|
||||||
fsStorageClose(&bis_storage);
|
}
|
||||||
rc = ResultFsPermissionDenied;
|
} else {
|
||||||
return rc;
|
if (is_sysmodule || has_bis_write_flag) {
|
||||||
}
|
/* Sysmodules should still be allowed to read and write. */
|
||||||
} else {
|
out_storage.SetValue(std::make_shared<IStorageInterface>(new ProxyStorage(bis_storage)));
|
||||||
if (is_sysmodule || has_bis_write_flag) {
|
} else if (Utils::IsHblTid(this->title_id) &&
|
||||||
/* Sysmodules should still be allowed to read and write. */
|
((FsBisStorageId_BootConfigAndPackage2NormalMain <= bis_partition_id && bis_partition_id <= FsBisStorageId_BootConfigAndPackage2RepairSub) ||
|
||||||
storage = std::make_shared<IStorageInterface>(new ProxyStorage(bis_storage));
|
bis_partition_id == FsBisStorageId_Boot1)) {
|
||||||
} else if (Utils::IsHblTid(this->title_id) &&
|
/* Allow HBL to write to boot1 (safe firm) + package2. */
|
||||||
((FsBisStorageId_BootConfigAndPackage2NormalMain <= bis_partition_id && bis_partition_id <= FsBisStorageId_BootConfigAndPackage2RepairSub) ||
|
/* This is needed to not break compatibility with ChoiDujourNX, which does not check for write access before beginning an update. */
|
||||||
bis_partition_id == FsBisStorageId_Boot1)) {
|
/* TODO: get fixed so that this can be turned off without causing bricks :/ */
|
||||||
/* Allow HBL to write to boot1 (safe firm) + package2. */
|
out_storage.SetValue(std::make_shared<IStorageInterface>(new ProxyStorage(bis_storage)));
|
||||||
/* This is needed to not break compatibility with ChoiDujourNX, which does not check for write access before beginning an update. */
|
} else {
|
||||||
/* TODO: get fixed so that this can be turned off without causing bricks :/ */
|
/* Non-sysmodules should be allowed to read. */
|
||||||
storage = std::make_shared<IStorageInterface>(new ProxyStorage(bis_storage));
|
out_storage.SetValue(std::make_shared<IStorageInterface>(new ReadOnlyStorageAdapter(new ProxyStorage(bis_storage))));
|
||||||
} else {
|
|
||||||
/* Non-sysmodules should be allowed to read. */
|
|
||||||
storage = std::make_shared<IStorageInterface>(new ReadOnlyStorageAdapter(new ProxyStorage(bis_storage)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (out_storage.IsDomain()) {
|
|
||||||
out_domain_id = bis_storage.s.object_id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
/* Copy domain id. */
|
||||||
|
if (out_storage.IsDomain()) {
|
||||||
|
out_storage.ChangeObjectId(bis_storage.s.object_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add redirection for RomFS to the SD card. */
|
/* Add redirection for RomFS to the SD card. */
|
||||||
Result FsMitmService::OpenDataStorageByCurrentProcess(Out<std::shared_ptr<IStorageInterface>> out_storage) {
|
Result FsMitmService::OpenDataStorageByCurrentProcess(Out<std::shared_ptr<IStorageInterface>> out_storage) {
|
||||||
std::shared_ptr<IStorageInterface> storage = nullptr;
|
|
||||||
u32 out_domain_id = 0;
|
|
||||||
Result rc = ResultSuccess;
|
|
||||||
|
|
||||||
if (!this->should_override_contents) {
|
if (!this->should_override_contents) {
|
||||||
return ResultAtmosphereMitmShouldForwardToSession;
|
return ResultAtmosphereMitmShouldForwardToSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_cache = StorageCacheGetEntry(this->title_id, &storage);
|
/* If we don't have anything to modify, there's no sense in maintaining a copy of the metadata tables. */
|
||||||
|
if (!Utils::HasSdRomfsContent(this->title_id)) {
|
||||||
|
return ResultAtmosphereMitmShouldForwardToSession;
|
||||||
|
}
|
||||||
|
|
||||||
ON_SCOPE_EXIT {
|
/* Try to get from the cache. */
|
||||||
if (R_SUCCEEDED(rc)) {
|
{
|
||||||
if (!has_cache) {
|
std::shared_ptr<IStorageInterface> cached_storage = nullptr;
|
||||||
StorageCacheSetEntry(this->title_id, &storage);
|
bool has_cache = StorageCacheGetEntry(this->title_id, &cached_storage);
|
||||||
}
|
|
||||||
|
|
||||||
out_storage.SetValue(std::move(storage));
|
if (has_cache) {
|
||||||
if (out_storage.IsDomain()) {
|
if (out_storage.IsDomain()) {
|
||||||
out_storage.ChangeObjectId(out_domain_id);
|
/* TODO: Don't leak object id? */
|
||||||
}
|
FsStorage s = {0};
|
||||||
}
|
R_TRY(fsOpenDataStorageByCurrentProcessFwd(this->forward_service.get(), &s));
|
||||||
};
|
out_storage.ChangeObjectId(s.s.object_id);
|
||||||
|
|
||||||
|
|
||||||
if (has_cache) {
|
|
||||||
if (out_storage.IsDomain()) {
|
|
||||||
FsStorage s = {0};
|
|
||||||
rc = fsOpenDataStorageByCurrentProcessFwd(this->forward_service.get(), &s);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
out_domain_id = s.s.object_id;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rc = ResultSuccess;
|
|
||||||
}
|
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
storage.reset();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FsStorage data_storage;
|
|
||||||
FsFile data_file;
|
|
||||||
|
|
||||||
rc = fsOpenDataStorageByCurrentProcessFwd(this->forward_service.get(), &data_storage);
|
|
||||||
|
|
||||||
Log(armGetTls(), 0x100);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
if (Utils::HasSdRomfsContent(this->title_id)) {
|
|
||||||
/* TODO: Is there a sensible path that ends in ".romfs" we can use?" */
|
|
||||||
if (R_SUCCEEDED(Utils::OpenSdFileForAtmosphere(this->title_id, "romfs.bin", FS_OPEN_READ, &data_file))) {
|
|
||||||
storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<ReadOnlyStorageAdapter>(new ProxyStorage(data_storage)), std::make_shared<ReadOnlyStorageAdapter>(new FileStorage(new ProxyFile(data_file))), this->title_id));
|
|
||||||
} else {
|
|
||||||
storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<ReadOnlyStorageAdapter>(new ProxyStorage(data_storage)), nullptr, this->title_id));
|
|
||||||
}
|
|
||||||
if (out_storage.IsDomain()) {
|
|
||||||
out_domain_id = data_storage.s.object_id;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* If we don't have anything to modify, there's no sense in maintaining a copy of the metadata tables. */
|
|
||||||
fsStorageClose(&data_storage);
|
|
||||||
rc = ResultAtmosphereMitmShouldForwardToSession;
|
|
||||||
}
|
}
|
||||||
|
out_storage.SetValue(std::move(cached_storage));
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
/* Try to open process romfs. */
|
||||||
|
FsStorage data_storage;
|
||||||
|
R_TRY(fsOpenDataStorageByCurrentProcessFwd(this->forward_service.get(), &data_storage));
|
||||||
|
|
||||||
|
/* Make new layered romfs, cacheing to storage. */
|
||||||
|
{
|
||||||
|
std::shared_ptr<IStorageInterface> storage_to_cache = nullptr;
|
||||||
|
/* TODO: Is there a sensible path that ends in ".romfs" we can use?" */
|
||||||
|
FsFile data_file;
|
||||||
|
if (R_SUCCEEDED(Utils::OpenSdFileForAtmosphere(this->title_id, "romfs.bin", FS_OPEN_READ, &data_file))) {
|
||||||
|
storage_to_cache = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<ReadOnlyStorageAdapter>(new ProxyStorage(data_storage)), std::make_shared<ReadOnlyStorageAdapter>(new FileStorage(new ProxyFile(data_file))), this->title_id));
|
||||||
|
} else {
|
||||||
|
storage_to_cache = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<ReadOnlyStorageAdapter>(new ProxyStorage(data_storage)), nullptr, this->title_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageCacheSetEntry(this->title_id, &storage_to_cache);
|
||||||
|
|
||||||
|
out_storage.SetValue(std::move(storage_to_cache));
|
||||||
|
if (out_storage.IsDomain()) {
|
||||||
|
out_storage.ChangeObjectId(data_storage.s.object_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add redirection for System Data Archives to the SD card. */
|
/* Add redirection for System Data Archives to the SD card. */
|
||||||
Result FsMitmService::OpenDataStorageByDataId(Out<std::shared_ptr<IStorageInterface>> out_storage, u64 data_id, u8 sid) {
|
Result FsMitmService::OpenDataStorageByDataId(Out<std::shared_ptr<IStorageInterface>> out_storage, u64 data_id, u8 sid) {
|
||||||
FsStorageId storage_id = (FsStorageId)sid;
|
|
||||||
FsStorage data_storage;
|
|
||||||
FsFile data_file;
|
|
||||||
|
|
||||||
if (!this->should_override_contents) {
|
if (!this->should_override_contents) {
|
||||||
return ResultAtmosphereMitmShouldForwardToSession;
|
return ResultAtmosphereMitmShouldForwardToSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<IStorageInterface> storage = nullptr;
|
/* If we don't have anything to modify, there's no sense in maintaining a copy of the metadata tables. */
|
||||||
u32 out_domain_id = 0;
|
if (!Utils::HasSdRomfsContent(data_id)) {
|
||||||
Result rc = ResultSuccess;
|
return ResultAtmosphereMitmShouldForwardToSession;
|
||||||
|
}
|
||||||
|
|
||||||
bool has_cache = StorageCacheGetEntry(data_id, &storage);
|
FsStorageId storage_id = static_cast<FsStorageId>(sid);
|
||||||
|
|
||||||
ON_SCOPE_EXIT {
|
/* Try to get from the cache. */
|
||||||
if (R_SUCCEEDED(rc)) {
|
{
|
||||||
if (!has_cache) {
|
std::shared_ptr<IStorageInterface> cached_storage = nullptr;
|
||||||
StorageCacheSetEntry(data_id, &storage);
|
bool has_cache = StorageCacheGetEntry(data_id, &cached_storage);
|
||||||
}
|
|
||||||
|
|
||||||
out_storage.SetValue(std::move(storage));
|
if (has_cache) {
|
||||||
if (out_storage.IsDomain()) {
|
if (out_storage.IsDomain()) {
|
||||||
out_storage.ChangeObjectId(out_domain_id);
|
/* TODO: Don't leak object id? */
|
||||||
}
|
FsStorage s = {0};
|
||||||
}
|
R_TRY(fsOpenDataStorageByDataIdFwd(this->forward_service.get(), storage_id, data_id, &s));
|
||||||
};
|
out_storage.ChangeObjectId(s.s.object_id);
|
||||||
|
|
||||||
if (has_cache) {
|
|
||||||
if (out_storage.IsDomain()) {
|
|
||||||
FsStorage s = {0};
|
|
||||||
rc = fsOpenDataStorageByDataIdFwd(this->forward_service.get(), storage_id, data_id, &s);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
out_domain_id = s.s.object_id;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rc = ResultSuccess;
|
|
||||||
}
|
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
storage.reset();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rc = fsOpenDataStorageByDataIdFwd(this->forward_service.get(), storage_id, data_id, &data_storage);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
if (Utils::HasSdRomfsContent(data_id)) {
|
|
||||||
/* TODO: Is there a sensible path that ends in ".romfs" we can use?" */
|
|
||||||
if (R_SUCCEEDED(Utils::OpenSdFileForAtmosphere(data_id, "romfs.bin", FS_OPEN_READ, &data_file))) {
|
|
||||||
storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<ReadOnlyStorageAdapter>(new ProxyStorage(data_storage)), std::make_shared<ReadOnlyStorageAdapter>(new FileStorage(new ProxyFile(data_file))), data_id));
|
|
||||||
} else {
|
|
||||||
storage = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<ReadOnlyStorageAdapter>(new ProxyStorage(data_storage)), nullptr, data_id));
|
|
||||||
}
|
|
||||||
if (out_storage.IsDomain()) {
|
|
||||||
out_domain_id = data_storage.s.object_id;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* If we don't have anything to modify, there's no sense in maintaining a copy of the metadata tables. */
|
|
||||||
fsStorageClose(&data_storage);
|
|
||||||
rc = ResultAtmosphereMitmShouldForwardToSession;
|
|
||||||
}
|
}
|
||||||
|
out_storage.SetValue(std::move(cached_storage));
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
/* Try to open data storage. */
|
||||||
|
FsStorage data_storage;
|
||||||
|
R_TRY(fsOpenDataStorageByDataIdFwd(this->forward_service.get(), storage_id, data_id, &data_storage));
|
||||||
|
|
||||||
|
/* Make new layered romfs, cacheing to storage. */
|
||||||
|
{
|
||||||
|
std::shared_ptr<IStorageInterface> storage_to_cache = nullptr;
|
||||||
|
/* TODO: Is there a sensible path that ends in ".romfs" we can use?" */
|
||||||
|
FsFile data_file;
|
||||||
|
if (R_SUCCEEDED(Utils::OpenSdFileForAtmosphere(data_id, "romfs.bin", FS_OPEN_READ, &data_file))) {
|
||||||
|
storage_to_cache = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<ReadOnlyStorageAdapter>(new ProxyStorage(data_storage)), std::make_shared<ReadOnlyStorageAdapter>(new FileStorage(new ProxyFile(data_file))), data_id));
|
||||||
|
} else {
|
||||||
|
storage_to_cache = std::make_shared<IStorageInterface>(new LayeredRomFS(std::make_shared<ReadOnlyStorageAdapter>(new ProxyStorage(data_storage)), nullptr, data_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageCacheSetEntry(data_id, &storage_to_cache);
|
||||||
|
|
||||||
|
out_storage.SetValue(std::move(storage_to_cache));
|
||||||
|
if (out_storage.IsDomain()) {
|
||||||
|
out_storage.ChangeObjectId(data_storage.s.object_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,24 +21,23 @@
|
|||||||
#include "fs_ifilesystem.hpp"
|
#include "fs_ifilesystem.hpp"
|
||||||
#include "../utils.hpp"
|
#include "../utils.hpp"
|
||||||
|
|
||||||
enum FspSrvCmd : u32 {
|
|
||||||
FspSrvCmd_OpenFileSystemDeprecated = 0,
|
|
||||||
|
|
||||||
FspSrvCmd_SetCurrentProcess = 1,
|
|
||||||
|
|
||||||
FspSrvCmd_OpenFileSystemWithPatch = 7,
|
|
||||||
FspSrvCmd_OpenFileSystemWithId = 8,
|
|
||||||
|
|
||||||
FspSrvCmd_OpenSdCardFileSystem = 18,
|
|
||||||
|
|
||||||
FspSrvCmd_OpenSaveDataFileSystem = 51,
|
|
||||||
|
|
||||||
FspSrvCmd_OpenBisStorage = 12,
|
|
||||||
FspSrvCmd_OpenDataStorageByCurrentProcess = 200,
|
|
||||||
FspSrvCmd_OpenDataStorageByDataId = 202,
|
|
||||||
};
|
|
||||||
|
|
||||||
class FsMitmService : public IMitmServiceObject {
|
class FsMitmService : public IMitmServiceObject {
|
||||||
|
private:
|
||||||
|
enum class CommandId {
|
||||||
|
OpenFileSystemDeprecated = 0,
|
||||||
|
|
||||||
|
SetCurrentProcess = 1,
|
||||||
|
OpenFileSystemWithPatch = 7,
|
||||||
|
OpenFileSystemWithId = 8,
|
||||||
|
|
||||||
|
OpenSdCardFileSystem = 18,
|
||||||
|
|
||||||
|
OpenSaveDataFileSystem = 51,
|
||||||
|
|
||||||
|
OpenBisStorage = 12,
|
||||||
|
OpenDataStorageByCurrentProcess = 200,
|
||||||
|
OpenDataStorageByDataId = 202,
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
static constexpr const char *AtmosphereHblWebContentDir = "/atmosphere/hbl_html";
|
static constexpr const char *AtmosphereHblWebContentDir = "/atmosphere/hbl_html";
|
||||||
private:
|
private:
|
||||||
@@ -84,13 +83,13 @@ class FsMitmService : public IMitmServiceObject {
|
|||||||
Result OpenDataStorageByDataId(Out<std::shared_ptr<IStorageInterface>> out, u64 data_id, u8 storage_id);
|
Result OpenDataStorageByDataId(Out<std::shared_ptr<IStorageInterface>> out, u64 data_id, u8 storage_id);
|
||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
/* TODO MakeServiceCommandMeta<FspSrvCmd_OpenFileSystemDeprecated, &FsMitmService::OpenFileSystemDeprecated>(), */
|
/* TODO MAKE_SERVICE_COMMAND_META(FsMitmService, OpenFileSystemDeprecated), */
|
||||||
MakeServiceCommandMeta<FspSrvCmd_OpenFileSystemWithPatch, &FsMitmService::OpenFileSystemWithPatch, FirmwareVersion_200>(),
|
MAKE_SERVICE_COMMAND_META(FsMitmService, OpenFileSystemWithPatch, FirmwareVersion_200),
|
||||||
MakeServiceCommandMeta<FspSrvCmd_OpenFileSystemWithId, &FsMitmService::OpenFileSystemWithId, FirmwareVersion_200>(),
|
MAKE_SERVICE_COMMAND_META(FsMitmService, OpenFileSystemWithId, FirmwareVersion_200),
|
||||||
MakeServiceCommandMeta<FspSrvCmd_OpenSdCardFileSystem, &FsMitmService::OpenSdCardFileSystem>(),
|
MAKE_SERVICE_COMMAND_META(FsMitmService, OpenSdCardFileSystem),
|
||||||
MakeServiceCommandMeta<FspSrvCmd_OpenSaveDataFileSystem, &FsMitmService::OpenSaveDataFileSystem>(),
|
MAKE_SERVICE_COMMAND_META(FsMitmService, OpenSaveDataFileSystem),
|
||||||
MakeServiceCommandMeta<FspSrvCmd_OpenBisStorage, &FsMitmService::OpenBisStorage>(),
|
MAKE_SERVICE_COMMAND_META(FsMitmService, OpenBisStorage),
|
||||||
MakeServiceCommandMeta<FspSrvCmd_OpenDataStorageByCurrentProcess, &FsMitmService::OpenDataStorageByCurrentProcess>(),
|
MAKE_SERVICE_COMMAND_META(FsMitmService, OpenDataStorageByCurrentProcess),
|
||||||
MakeServiceCommandMeta<FspSrvCmd_OpenDataStorageByDataId, &FsMitmService::OpenDataStorageByDataId>(),
|
MAKE_SERVICE_COMMAND_META(FsMitmService, OpenDataStorageByDataId),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,10 +29,13 @@ Result NsAmMitmService::GetApplicationContentPath(OutBuffer<u8> out_path, u64 ap
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result NsAmMitmService::ResolveApplicationContentPath(u64 title_id, u8 storage_type) {
|
Result NsAmMitmService::ResolveApplicationContentPath(u64 title_id, u8 storage_type) {
|
||||||
Result rc = nsamResolveApplicationContentPathFwd(this->forward_service.get(), title_id, static_cast<FsStorageId>(storage_type));
|
|
||||||
|
|
||||||
/* Always succeed for web applet asking about HBL. */
|
/* Always succeed for web applet asking about HBL. */
|
||||||
return (Utils::IsWebAppletTid(this->title_id) && Utils::IsHblTid(title_id)) ? 0 : rc;
|
if (Utils::IsWebAppletTid(this->title_id) && Utils::IsHblTid(title_id)) {
|
||||||
|
nsamResolveApplicationContentPathFwd(this->forward_service.get(), title_id, static_cast<FsStorageId>(storage_type));
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nsamResolveApplicationContentPathFwd(this->forward_service.get(), title_id, static_cast<FsStorageId>(storage_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result NsAmMitmService::GetRunningApplicationProgramId(Out<u64> out_tid, u64 app_id) {
|
Result NsAmMitmService::GetRunningApplicationProgramId(Out<u64> out_tid, u64 app_id) {
|
||||||
|
|||||||
@@ -13,30 +13,34 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "../utils.hpp"
|
#include "../utils.hpp"
|
||||||
|
|
||||||
#include "nsmitm_service_common.hpp"
|
class NsAmMitmService : public IMitmServiceObject {
|
||||||
|
private:
|
||||||
class NsAmMitmService : public IMitmServiceObject {
|
enum class CommandId {
|
||||||
|
GetApplicationContentPath = 21,
|
||||||
|
ResolveApplicationContentPath = 23,
|
||||||
|
GetRunningApplicationProgramId = 92,
|
||||||
|
};
|
||||||
public:
|
public:
|
||||||
NsAmMitmService(std::shared_ptr<Service> s, u64 pid) : IMitmServiceObject(s, pid) {
|
NsAmMitmService(std::shared_ptr<Service> s, u64 pid) : IMitmServiceObject(s, pid) {
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ShouldMitm(u64 pid, u64 tid) {
|
static bool ShouldMitm(u64 pid, u64 tid) {
|
||||||
/* We will mitm:
|
/* We will mitm:
|
||||||
* - web applets, to facilitate hbl web browser launching.
|
* - web applets, to facilitate hbl web browser launching.
|
||||||
*/
|
*/
|
||||||
return Utils::IsWebAppletTid(tid);
|
return Utils::IsWebAppletTid(tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx);
|
static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* Overridden commands. */
|
/* Overridden commands. */
|
||||||
Result GetApplicationContentPath(OutBuffer<u8> out_path, u64 app_id, u8 storage_type);
|
Result GetApplicationContentPath(OutBuffer<u8> out_path, u64 app_id, u8 storage_type);
|
||||||
@@ -44,8 +48,8 @@ class NsAmMitmService : public IMitmServiceObject {
|
|||||||
Result GetRunningApplicationProgramId(Out<u64> out_tid, u64 app_id);
|
Result GetRunningApplicationProgramId(Out<u64> out_tid, u64 app_id);
|
||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MakeServiceCommandMeta<NsSrvCmd_GetApplicationContentPath, &NsAmMitmService::GetApplicationContentPath>(),
|
MAKE_SERVICE_COMMAND_META(NsAmMitmService, GetApplicationContentPath),
|
||||||
MakeServiceCommandMeta<NsSrvCmd_ResolveApplicationContentPath, &NsAmMitmService::ResolveApplicationContentPath>(),
|
MAKE_SERVICE_COMMAND_META(NsAmMitmService, ResolveApplicationContentPath),
|
||||||
MakeServiceCommandMeta<NsSrvCmd_GetRunningApplicationProgramId, &NsAmMitmService::GetRunningApplicationProgramId, FirmwareVersion_600>(),
|
MAKE_SERVICE_COMMAND_META(NsAmMitmService, GetRunningApplicationProgramId, FirmwareVersion_600),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -36,26 +36,21 @@ void NsMitmMain(void *arg) {
|
|||||||
|
|
||||||
/* Ensure we can talk to NS. */
|
/* Ensure we can talk to NS. */
|
||||||
DoWithSmSession([&]() {
|
DoWithSmSession([&]() {
|
||||||
if (R_FAILED(nsInitialize())) {
|
R_ASSERT(nsInitialize());
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
nsExit();
|
|
||||||
});
|
});
|
||||||
|
nsExit();
|
||||||
|
|
||||||
/* Create server manager */
|
/* Create server manager */
|
||||||
auto server_manager = new WaitableManager(1);
|
static auto s_server_manager = WaitableManager(1);
|
||||||
|
|
||||||
/* Create ns mitm. */
|
/* Create ns mitm. */
|
||||||
if (GetRuntimeFirmwareVersion() < FirmwareVersion_300) {
|
if (GetRuntimeFirmwareVersion() < FirmwareVersion_300) {
|
||||||
AddMitmServerToManager<NsAmMitmService>(server_manager, "ns:am", 5);
|
AddMitmServerToManager<NsAmMitmService>(&s_server_manager, "ns:am", 5);
|
||||||
} else {
|
} else {
|
||||||
AddMitmServerToManager<NsWebMitmService>(server_manager, "ns:web", 5);
|
AddMitmServerToManager<NsWebMitmService>(&s_server_manager, "ns:web", 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop forever, servicing our services. */
|
/* Loop forever, servicing our services. */
|
||||||
server_manager->Process();
|
s_server_manager.Process();
|
||||||
|
|
||||||
delete server_manager;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|||||||
@@ -24,30 +24,17 @@ void NsWebMitmService::PostProcess(IMitmServiceObject *obj, IpcResponseContext *
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result NsWebMitmService::GetDocumentInterface(Out<std::shared_ptr<NsDocumentService>> out_intf) {
|
Result NsWebMitmService::GetDocumentInterface(Out<std::shared_ptr<NsDocumentService>> out_intf) {
|
||||||
std::shared_ptr<NsDocumentService> intf = nullptr;
|
|
||||||
u32 out_domain_id = 0;
|
|
||||||
Result rc = ResultSuccess;
|
|
||||||
|
|
||||||
ON_SCOPE_EXIT {
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
out_intf.SetValue(std::move(intf));
|
|
||||||
if (out_intf.IsDomain()) {
|
|
||||||
out_intf.ChangeObjectId(out_domain_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Open a document interface. */
|
/* Open a document interface. */
|
||||||
NsDocumentInterface doc;
|
NsDocumentInterface doc;
|
||||||
rc = nsGetDocumentInterfaceFwd(this->forward_service.get(), &doc);
|
R_TRY(nsGetDocumentInterfaceFwd(this->forward_service.get(), &doc));
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
intf = std::make_shared<NsDocumentService>(this->title_id, doc);
|
/* Set output interface. */
|
||||||
if (out_intf.IsDomain()) {
|
out_intf.SetValue(std::move(std::make_shared<NsDocumentService>(this->title_id, doc)));
|
||||||
out_domain_id = doc.s.object_id;
|
if (out_intf.IsDomain()) {
|
||||||
}
|
out_intf.ChangeObjectId(doc.s.object_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result NsDocumentService::GetApplicationContentPath(OutBuffer<u8> out_path, u64 app_id, u8 storage_type) {
|
Result NsDocumentService::GetApplicationContentPath(OutBuffer<u8> out_path, u64 app_id, u8 storage_type) {
|
||||||
@@ -55,10 +42,13 @@ Result NsDocumentService::GetApplicationContentPath(OutBuffer<u8> out_path, u64
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result NsDocumentService::ResolveApplicationContentPath(u64 title_id, u8 storage_type) {
|
Result NsDocumentService::ResolveApplicationContentPath(u64 title_id, u8 storage_type) {
|
||||||
Result rc = nswebResolveApplicationContentPath(this->srv.get(), title_id, static_cast<FsStorageId>(storage_type));
|
|
||||||
|
|
||||||
/* Always succeed for web applet asking about HBL. */
|
/* Always succeed for web applet asking about HBL. */
|
||||||
return (Utils::IsWebAppletTid(this->title_id) && Utils::IsHblTid(title_id)) ? 0 : rc;
|
if (Utils::IsWebAppletTid(this->title_id) && Utils::IsHblTid(title_id)) {
|
||||||
|
nswebResolveApplicationContentPath(this->srv.get(), title_id, static_cast<FsStorageId>(storage_type));
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nswebResolveApplicationContentPath(this->srv.get(), title_id, static_cast<FsStorageId>(storage_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result NsDocumentService::GetRunningApplicationProgramId(Out<u64> out_tid, u64 app_id) {
|
Result NsDocumentService::GetRunningApplicationProgramId(Out<u64> out_tid, u64 app_id) {
|
||||||
|
|||||||
@@ -13,17 +13,22 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
#include "../utils.hpp"
|
#include "../utils.hpp"
|
||||||
|
|
||||||
#include "nsmitm_service_common.hpp"
|
|
||||||
#include "ns_shim.h"
|
#include "ns_shim.h"
|
||||||
|
|
||||||
class NsDocumentService : public IServiceObject {
|
class NsDocumentService : public IServiceObject {
|
||||||
|
private:
|
||||||
|
enum class CommandId {
|
||||||
|
GetApplicationContentPath = 21,
|
||||||
|
ResolveApplicationContentPath = 23,
|
||||||
|
GetRunningApplicationProgramId = 92,
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
u64 title_id;
|
u64 title_id;
|
||||||
std::unique_ptr<NsDocumentInterface> srv;
|
std::unique_ptr<NsDocumentInterface> srv;
|
||||||
@@ -50,32 +55,36 @@ class NsDocumentService : public IServiceObject {
|
|||||||
Result GetRunningApplicationProgramId(Out<u64> out_tid, u64 app_id);
|
Result GetRunningApplicationProgramId(Out<u64> out_tid, u64 app_id);
|
||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MakeServiceCommandMeta<NsSrvCmd_GetApplicationContentPath, &NsDocumentService::GetApplicationContentPath>(),
|
MAKE_SERVICE_COMMAND_META(NsDocumentService, GetApplicationContentPath),
|
||||||
MakeServiceCommandMeta<NsSrvCmd_ResolveApplicationContentPath, &NsDocumentService::ResolveApplicationContentPath>(),
|
MAKE_SERVICE_COMMAND_META(NsDocumentService, ResolveApplicationContentPath),
|
||||||
MakeServiceCommandMeta<NsSrvCmd_GetRunningApplicationProgramId, &NsDocumentService::GetRunningApplicationProgramId, FirmwareVersion_600>(),
|
MAKE_SERVICE_COMMAND_META(NsDocumentService, GetRunningApplicationProgramId, FirmwareVersion_600),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class NsWebMitmService : public IMitmServiceObject {
|
class NsWebMitmService : public IMitmServiceObject {
|
||||||
|
private:
|
||||||
|
enum class CommandId {
|
||||||
|
GetDocumentInterface = 7999,
|
||||||
|
};
|
||||||
public:
|
public:
|
||||||
NsWebMitmService(std::shared_ptr<Service> s, u64 pid) : IMitmServiceObject(s, pid) {
|
NsWebMitmService(std::shared_ptr<Service> s, u64 pid) : IMitmServiceObject(s, pid) {
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ShouldMitm(u64 pid, u64 tid) {
|
static bool ShouldMitm(u64 pid, u64 tid) {
|
||||||
/* We will mitm:
|
/* We will mitm:
|
||||||
* - web applets, to facilitate hbl web browser launching.
|
* - web applets, to facilitate hbl web browser launching.
|
||||||
*/
|
*/
|
||||||
return Utils::IsWebAppletTid(tid);
|
return Utils::IsWebAppletTid(tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx);
|
static void PostProcess(IMitmServiceObject *obj, IpcResponseContext *ctx);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* Overridden commands. */
|
/* Overridden commands. */
|
||||||
Result GetDocumentInterface(Out<std::shared_ptr<NsDocumentService>> out_intf);
|
Result GetDocumentInterface(Out<std::shared_ptr<NsDocumentService>> out_intf);
|
||||||
public:
|
public:
|
||||||
DEFINE_SERVICE_DISPATCH_TABLE {
|
DEFINE_SERVICE_DISPATCH_TABLE {
|
||||||
MakeServiceCommandMeta<NsGetterCmd_GetDocumentInterface, &NsWebMitmService::GetDocumentInterface, FirmwareVersion_300>(),
|
MAKE_SERVICE_COMMAND_META(NsWebMitmService, GetDocumentInterface, FirmwareVersion_300),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ bool SetMitmService::IsValidRegionCode(u32 region_code) {
|
|||||||
return region_code < RegionCode_Max;
|
return region_code < RegionCode_Max;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetMitmService::EnsureLocale() {
|
Result SetMitmService::EnsureLocale() {
|
||||||
std::scoped_lock<HosMutex> lk(this->lock);
|
std::scoped_lock<HosMutex> lk(this->lock);
|
||||||
|
|
||||||
if (!this->got_locale) {
|
if (!this->got_locale) {
|
||||||
@@ -71,19 +71,16 @@ void SetMitmService::EnsureLocale() {
|
|||||||
if (this->title_id == TitleId_Ns) {
|
if (this->title_id == TitleId_Ns) {
|
||||||
u64 app_pid = 0;
|
u64 app_pid = 0;
|
||||||
u64 app_tid = 0;
|
u64 app_tid = 0;
|
||||||
Result rc;
|
R_TRY(pmdmntGetApplicationPid(&app_pid));
|
||||||
if (R_FAILED((rc = pmdmntGetApplicationPid(&app_pid)))) {
|
R_TRY(pminfoGetTitleId(&app_tid, app_pid));
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (R_FAILED((rc = pminfoGetTitleId(&app_tid, app_pid)))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this->locale = Utils::GetTitleOverrideLocale(app_tid);
|
this->locale = Utils::GetTitleOverrideLocale(app_tid);
|
||||||
} else {
|
} else {
|
||||||
this->locale = Utils::GetTitleOverrideLocale(this->title_id);
|
this->locale = Utils::GetTitleOverrideLocale(this->title_id);
|
||||||
this->got_locale = true;
|
this->got_locale = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetMitmService::GetLanguageCode(Out<u64> out_lang_code) {
|
Result SetMitmService::GetLanguageCode(Out<u64> out_lang_code) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user