mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-04-22 12:34:47 +00:00
Merge remote-tracking branch 'upstream/master' into ncm
This commit is contained in:
commit
70f84e0511
21 changed files with 430 additions and 84 deletions
|
@ -28,6 +28,7 @@ You can find a copy of the license in the [LICENSE file](LICENSE).
|
|||
|
||||
Exemptions:
|
||||
* The [yuzu emulator project](https://github.com/yuzu-emu/yuzu) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the Atmosphère project as GPLv2 or later.
|
||||
* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the Atmosphère project under the Zero-Clause BSD license.
|
||||
|
||||
Credits
|
||||
=====
|
||||
|
|
|
@ -1,4 +1,18 @@
|
|||
# Changelog
|
||||
## 0.10.3
|
||||
+ Support was added for 9.2.0.
|
||||
+ Support was added for redirecting manual html content for games.
|
||||
+ This works like normal layeredfs, replacing content placed in `/atmosphere/contents/<program id>/manual_html/`.
|
||||
+ This allows for game mods/translations to provide custom manual content, if they so choose.
|
||||
+ A number of improvements were made to Atmosphere's memory usage, including:
|
||||
+ `fatal` now uses STB instead of freetype for rendering.
|
||||
+ This saves around 1 MB of memory, and makes our fatal substantially leaner than Nintendo's.
|
||||
+ `sm` no longer wastes 2 MiB unnecessarily.
|
||||
+ fusee/sept's sdmmc access now better matches official behavior.
|
||||
+ This improves compatibility with some SD cards.
|
||||
+ `ro` has been updated to reflect changes made in 9.1.0.
|
||||
+ The temporary auto-migration added in 0.10.0 has been removed, since the transitionary period is well over.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 0.10.2
|
||||
+ hbl configuration was made more flexible.
|
||||
+ Up to eight specific program ids can now be specified to have their own override keys.
|
||||
|
|
|
@ -801,6 +801,16 @@ static const kernel_info_t g_kernel_infos[] = {
|
|||
.embedded_ini_ptr = 0x180,
|
||||
.free_code_space_offset = 0x65780,
|
||||
KERNEL_PATCHES(900)
|
||||
},
|
||||
{ /* 9.2.0. */
|
||||
/* NOTE: 9.2.0 has identical kernel layout to 9.0.0, so patches may be reused. */
|
||||
.hash = {0x66, 0xE7, 0x73, 0xE7, 0xF5, 0xCB, 0x9B, 0xB8, 0x66, 0xB7, 0xB1, 0x26, 0x23, 0x02, 0x76, 0xF2, 0xD1, 0x60, 0x3E, 0x09, 0x14, 0x19, 0xC2, 0x84, 0xFA, 0x5D, 0x0F, 0x16, 0xA3, 0x65, 0xFA, 0x17},
|
||||
.hash_offset = 0x1C0,
|
||||
.hash_size = 0x90000 - 0x1C0,
|
||||
.embedded_ini_offset = 0x90000,
|
||||
.embedded_ini_ptr = 0x180,
|
||||
.free_code_space_offset = 0x65780,
|
||||
KERNEL_PATCHES(900)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
[subrepo]
|
||||
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
|
||||
branch = master
|
||||
commit = 08c9b3cbf85471fe6adb5f42ba9f03357a5f633a
|
||||
parent = 814c9d1cfb54c192bc1deb140ab476c9f3dd0edf
|
||||
commit = 83aa6133ee2eb43287f8fc373d309a0c99337429
|
||||
parent = fd34e2342a66b2aa3062ea7cecaf9728f12ef21a
|
||||
method = merge
|
||||
cmdver = 0.4.0
|
||||
cmdver = 0.4.1
|
||||
|
|
|
@ -11,6 +11,7 @@ You can find a copy of the license in the [LICENSE file](LICENSE).
|
|||
|
||||
Exemptions:
|
||||
* The [yuzu emulator project](https://github.com/yuzu-emu/yuzu) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the atmosphere-libs project as GPLv2 or later.
|
||||
* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the atmosphere-libs project under the Zero-Clause BSD license.
|
||||
|
||||
Credits
|
||||
=====
|
||||
|
|
|
@ -11,6 +11,7 @@ You can find a copy of the license in the [LICENSE file](LICENSE).
|
|||
|
||||
Exemptions:
|
||||
* The [yuzu emulator project](https://github.com/yuzu-emu/yuzu) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the libmesosphere project as GPLv2 or later.
|
||||
* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the libmesosphere project under the Zero-Clause BSD license.
|
||||
|
||||
Credits
|
||||
=====
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace ams::kern::init {
|
|||
constexpr size_t SlabCountKTransferMemory = 200;
|
||||
constexpr size_t SlabCountKCodeMemory = 10;
|
||||
constexpr size_t SlabCountKDeviceAddressSpace = 300;
|
||||
constexpr size_t SlabCountKSession = 900;
|
||||
constexpr size_t SlabCountKSession = 933;
|
||||
constexpr size_t SlabCountKLightSession = 100;
|
||||
constexpr size_t SlabCountKObjectName = 7;
|
||||
constexpr size_t SlabCountKResourceLimit = 5;
|
||||
|
|
|
@ -15,6 +15,7 @@ You can find a copy of the license in the [LICENSE file](LICENSE).
|
|||
|
||||
Exemptions:
|
||||
* The [yuzu emulator project](https://github.com/yuzu-emu/yuzu) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the libstratosphere project as GPLv2 or later.
|
||||
* [Nintendo](https://github.com/Nintendo) is exempt from GPLv2 licensing and may (at its option) instead license any source code authored for the libstratosphere project under the Zero-Clause BSD license.
|
||||
|
||||
Credits
|
||||
=====
|
||||
|
@ -29,3 +30,4 @@ In addition to those credited in [Atmosphère's credits](https://github.com/Atmo
|
|||
* __misson20000__
|
||||
* __neobrain__
|
||||
* __yellows8__
|
||||
* @[Nintendo](https://github.com/Nintendo)
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere/fs/fs_common.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifile.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_idirectory.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
class ReadOnlyFileAdapter : public fsa::IFile {
|
||||
NON_COPYABLE(ReadOnlyFileAdapter);
|
||||
private:
|
||||
std::unique_ptr<fsa::IFile> base_file;
|
||||
public:
|
||||
ReadOnlyFileAdapter(fsa::IFile *f) : base_file(f) { /* ... */ }
|
||||
ReadOnlyFileAdapter(std::unique_ptr<fsa::IFile> f) : base_file(std::move(f)) { /* ... */ }
|
||||
virtual ~ReadOnlyFileAdapter() { /* ... */ }
|
||||
public:
|
||||
virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final {
|
||||
/* Ensure that we can read these extents. */
|
||||
size_t read_size = 0;
|
||||
R_TRY(this->DryRead(std::addressof(read_size), offset, size, option, fs::OpenMode_Read));
|
||||
|
||||
/* Validate preconditions. */
|
||||
AMS_ASSERT(offset >= 0);
|
||||
AMS_ASSERT(buffer != nullptr || size == 0);
|
||||
|
||||
return this->base_file->Read(out, offset, buffer, size, option);
|
||||
}
|
||||
|
||||
virtual Result GetSizeImpl(s64 *out) override final {
|
||||
return this->base_file->GetSize(out);
|
||||
}
|
||||
|
||||
virtual Result FlushImpl() override final {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result SetSizeImpl(s64 size) override final {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result OperateRangeImpl(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final {
|
||||
/* TODO: How should this be handled? */
|
||||
return fs::ResultNotImplemented();
|
||||
}
|
||||
public:
|
||||
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override {
|
||||
return this->base_file->GetDomainObjectId();
|
||||
}
|
||||
};
|
||||
|
||||
class ReadOnlyFileSystemAdapter : public fsa::IFileSystem {
|
||||
NON_COPYABLE(ReadOnlyFileSystemAdapter);
|
||||
private:
|
||||
std::shared_ptr<fsa::IFileSystem> shared_fs;
|
||||
std::unique_ptr<fsa::IFileSystem> unique_fs;
|
||||
protected:
|
||||
fsa::IFileSystem * const base_fs;
|
||||
public:
|
||||
template<typename T>
|
||||
explicit ReadOnlyFileSystemAdapter(std::shared_ptr<T> fs) : shared_fs(std::move(fs)), base_fs(shared_fs.get()) { static_assert(std::is_base_of<fsa::IFileSystem, T>::value); }
|
||||
|
||||
template<typename T>
|
||||
explicit ReadOnlyFileSystemAdapter(std::unique_ptr<T> fs) : unique_fs(std::move(fs)), base_fs(unique_fs.get()) { static_assert(std::is_base_of<fsa::IFileSystem, T>::value); }
|
||||
|
||||
virtual ~ReadOnlyFileSystemAdapter() { /* ... */ }
|
||||
public:
|
||||
virtual Result CreateFileImpl(const char *path, s64 size, int flags) override final {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result DeleteFileImpl(const char *path) override final {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result CreateDirectoryImpl(const char *path) override final {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result DeleteDirectoryImpl(const char *path) override final {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override final {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result RenameFileImpl(const char *old_path, const char *new_path) override final {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override final {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const char *path) override final {
|
||||
return this->base_fs->GetEntryType(out, path);
|
||||
}
|
||||
|
||||
virtual Result OpenFileImpl(std::unique_ptr<fsa::IFile> *out_file, const char *path, OpenMode mode) override final {
|
||||
std::unique_ptr<fsa::IFile> f;
|
||||
R_TRY(this->base_fs->OpenFile(std::addressof(f), path, mode));
|
||||
|
||||
*out_file = std::make_unique<ReadOnlyFileAdapter>(std::move(f));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result OpenDirectoryImpl(std::unique_ptr<fsa::IDirectory> *out_dir, const char *path, OpenDirectoryMode mode) override final {
|
||||
return this->base_fs->OpenDirectory(out_dir, path, mode);
|
||||
}
|
||||
|
||||
virtual Result CommitImpl() override final {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result CleanDirectoryRecursivelyImpl(const char *path) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result GetFileTimeStampRawImpl(FileTimeStampRaw *out, const char *path) {
|
||||
return this->base_fs->GetFileTimeStampRaw(out, path);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -83,20 +83,22 @@ namespace ams::fs::fsa {
|
|||
/* TODO: This is a hack to allow the mitm API to work. Find a better way? */
|
||||
virtual sf::cmif::DomainObjectId GetDomainObjectId() const = 0;
|
||||
protected:
|
||||
Result DryRead(size_t *out, s64 offset, size_t size, const ReadOption &option, fs::OpenMode mode) {
|
||||
R_UNLESS((mode & fs::OpenMode_Read) != 0, fs::ResultInvalidOperationForOpenMode());
|
||||
Result DryRead(size_t *out, s64 offset, size_t size, const fs::ReadOption &option, OpenMode open_mode) {
|
||||
/* Check that we can read. */
|
||||
R_UNLESS((open_mode & OpenMode_Read) != 0, fs::ResultInvalidOperationForOpenMode());
|
||||
|
||||
/* Get the file size, and validate our offset. */
|
||||
s64 file_size = 0;
|
||||
R_TRY(this->GetSize(std::addressof(file_size)));
|
||||
R_TRY(this->GetSize(&file_size));
|
||||
R_UNLESS(offset <= file_size, fs::ResultOutOfRange());
|
||||
|
||||
const size_t readable_size = file_size - offset;
|
||||
*out = std::min(readable_size, size);
|
||||
*out = static_cast<size_t>(std::min(file_size - offset, static_cast<s64>(size)));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result DrySetSize(s64 size, fs::OpenMode mode) {
|
||||
R_UNLESS((mode & fs::OpenMode_Write) != 0, fs::ResultInvalidOperationForOpenMode());
|
||||
Result DrySetSize(s64 size, fs::OpenMode open_mode) {
|
||||
/* Check that we can write. */
|
||||
R_UNLESS((open_mode & OpenMode_Write) != 0, fs::ResultInvalidOperationForOpenMode());
|
||||
|
||||
AMS_ASSERT(size >= 0);
|
||||
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MINOR 10
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 2
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 3
|
||||
|
||||
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
|
||||
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 9
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 2
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
|
||||
|
|
|
@ -69,12 +69,12 @@ typedef u32 Result; ///< Function error code result type.
|
|||
|
||||
/// Creates a bitmask for bit range extraction.
|
||||
#ifndef MASK2
|
||||
#define MASK2(a,b) (MASK(a) & ~MASK(b))
|
||||
#define MASK2(a,b) (MASK((a) + 1) & ~MASK(b))
|
||||
#endif
|
||||
|
||||
/// Creates a bitmask for bit range extraction (long).
|
||||
#ifndef MASK2L
|
||||
#define MASK2L(a,b) (MASKL(a) & ~MASKL(b))
|
||||
#define MASK2L(a,b) (MASKL((a) + 1) & ~MASKL(b))
|
||||
#endif
|
||||
|
||||
/// Marks a function as not returning, for the purposes of compiler optimization.
|
||||
|
|
|
@ -32,38 +32,6 @@ namespace ams::mitm::fs {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, const char *src_path) {
|
||||
if (src_path[0] == '/') {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere%s", src_path);
|
||||
} else {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere/%s", src_path);
|
||||
}
|
||||
}
|
||||
|
||||
void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, const char *subdir, const char *src_path) {
|
||||
if (src_path[0] == '/') {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere/%s%s", subdir, src_path);
|
||||
} else {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere/%s/%s", subdir, src_path);
|
||||
}
|
||||
}
|
||||
|
||||
void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *src_path) {
|
||||
if (src_path[0] == '/') {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx%s", static_cast<u64>(program_id), src_path);
|
||||
} else {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx/%s", static_cast<u64>(program_id), src_path);
|
||||
}
|
||||
}
|
||||
|
||||
void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *subdir, const char *src_path) {
|
||||
if (src_path[0] == '/') {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx/%s%s", static_cast<u64>(program_id), subdir, src_path);
|
||||
} else {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx/%s/%s", static_cast<u64>(program_id), subdir, src_path);
|
||||
}
|
||||
}
|
||||
|
||||
void FormatAtmosphereRomfsPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *src_path) {
|
||||
return FormatAtmosphereSdPath(dst_path, dst_path_size, program_id, "romfs", src_path);
|
||||
}
|
||||
|
@ -154,14 +122,36 @@ namespace ams::mitm::fs {
|
|||
return fsFsOpenDirectory(fs, fixed_path, mode, out);
|
||||
}
|
||||
|
||||
/* TODO: Remove this in Atmosphere 0.10.2. */
|
||||
Result RenameProgramDirectoryForCompatibility(const char *dir_name) {
|
||||
R_TRY(EnsureSdInitialized());
|
||||
char titles_fixed_path[ams::fs::EntryNameLengthMax + 1];
|
||||
char contents_fixed_path[ams::fs::EntryNameLengthMax + 1];
|
||||
FormatAtmosphereSdPath(titles_fixed_path, sizeof(titles_fixed_path), "titles", dir_name);
|
||||
FormatAtmosphereSdPath(contents_fixed_path, sizeof(contents_fixed_path), "contents", dir_name);
|
||||
return fsFsRenameDirectory(&g_sd_filesystem, titles_fixed_path, contents_fixed_path);
|
||||
void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, const char *src_path) {
|
||||
if (src_path[0] == '/') {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere%s", src_path);
|
||||
} else {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere/%s", src_path);
|
||||
}
|
||||
}
|
||||
|
||||
void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, const char *subdir, const char *src_path) {
|
||||
if (src_path[0] == '/') {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere/%s%s", subdir, src_path);
|
||||
} else {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere/%s/%s", subdir, src_path);
|
||||
}
|
||||
}
|
||||
|
||||
void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *src_path) {
|
||||
if (src_path[0] == '/') {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx%s", static_cast<u64>(program_id), src_path);
|
||||
} else {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx/%s", static_cast<u64>(program_id), src_path);
|
||||
}
|
||||
}
|
||||
|
||||
void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *subdir, const char *src_path) {
|
||||
if (src_path[0] == '/') {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx/%s%s", static_cast<u64>(program_id), subdir, src_path);
|
||||
} else {
|
||||
std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx/%s/%s", static_cast<u64>(program_id), subdir, src_path);
|
||||
}
|
||||
}
|
||||
|
||||
bool HasSdRomfsContent(ncm::ProgramId program_id) {
|
||||
|
|
|
@ -38,8 +38,10 @@ namespace ams::mitm::fs {
|
|||
Result OpenAtmosphereSdRomfsDirectory(FsDir *out, ncm::ProgramId program_id, const char *path, u32 mode);
|
||||
Result OpenAtmosphereRomfsDirectory(FsDir *out, ncm::ProgramId program_id, const char *path, u32 mode, FsFileSystem *fs);
|
||||
|
||||
/* TODO: Remove this in Atmosphere 0.10.2. */
|
||||
Result RenameProgramDirectoryForCompatibility(const char *dir_name);
|
||||
void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, const char *src_path);
|
||||
void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, const char *subdir, const char *src_path);
|
||||
void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *src_path);
|
||||
void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *subdir, const char *src_path);
|
||||
|
||||
bool HasSdRomfsContent(ncm::ProgramId program_id);
|
||||
|
||||
|
|
|
@ -179,23 +179,6 @@ namespace ams::mitm {
|
|||
}
|
||||
}
|
||||
|
||||
void RenameTitlesDirectoryProgramFoldersForCompatibility() {
|
||||
FsDir titles_dir;
|
||||
if (R_FAILED(mitm::fs::OpenAtmosphereSdDirectory(&titles_dir, "/titles", ams::fs::OpenDirectoryMode_Directory))) {
|
||||
return;
|
||||
}
|
||||
ON_SCOPE_EXIT { fsDirClose(&titles_dir); };
|
||||
|
||||
ams::fs::DirectoryEntry dir_entry;
|
||||
s64 read_entries;
|
||||
while (R_SUCCEEDED(fsDirRead(&titles_dir, &read_entries, 1, &dir_entry)) && read_entries == 1) {
|
||||
if (strlen(dir_entry.name) == 2 * sizeof(ncm::ProgramId) && IsHexadecimal(dir_entry.name)) {
|
||||
/* We found a program directory, try to rename it. Failure is allowed. */
|
||||
mitm::fs::RenameProgramDirectoryForCompatibility(dir_entry.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialization implementation */
|
||||
void InitializeThreadFunc(void *arg) {
|
||||
/* Wait for the SD card to be ready. */
|
||||
|
@ -211,10 +194,6 @@ namespace ams::mitm {
|
|||
/* Backup Calibration Binary and BIS keys. */
|
||||
CreateAutomaticBackups();
|
||||
|
||||
/* Rename program folders in the titles directory. */
|
||||
/* TODO: Remove this in Atmosphere 0.10.2. */
|
||||
RenameTitlesDirectoryProgramFoldersForCompatibility();
|
||||
|
||||
/* If we're emummc, persist a write-handle to prevent other processes from touching the image. */
|
||||
if (emummc::IsActive()) {
|
||||
if (const char *emummc_file_path = emummc::GetFilePath(); emummc_file_path != nullptr) {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "fsmitm_boot0storage.hpp"
|
||||
#include "fsmitm_layered_romfs_storage.hpp"
|
||||
#include "fsmitm_save_utils.hpp"
|
||||
#include "fsmitm_readonly_layered_filesystem.hpp"
|
||||
|
||||
namespace ams::mitm::fs {
|
||||
|
||||
|
@ -27,6 +28,7 @@ namespace ams::mitm::fs {
|
|||
namespace {
|
||||
|
||||
constexpr const char AtmosphereHblWebContentDir[] = "/atmosphere/hbl_html/";
|
||||
constexpr const char ProgramWebContentDir[] = "/manual_html/";
|
||||
|
||||
os::Mutex g_data_storage_lock;
|
||||
os::Mutex g_storage_cache_lock;
|
||||
|
@ -67,8 +69,6 @@ namespace ams::mitm::fs {
|
|||
Result OpenHblWebContentFileSystem(sf::Out<std::shared_ptr<IFileSystemInterface>> &out, ncm::ProgramId client_program_id, ncm::ProgramId program_id, FsFileSystemType filesystem_type) {
|
||||
/* Verify eligibility. */
|
||||
bool is_hbl;
|
||||
R_UNLESS(ncm::IsWebAppletId(client_program_id), sm::mitm::ResultShouldForwardToSession());
|
||||
R_UNLESS(filesystem_type == FsFileSystemType_ContentManual, sm::mitm::ResultShouldForwardToSession());
|
||||
R_UNLESS(R_SUCCEEDED(pm::info::IsHblProgramId(&is_hbl, program_id)), sm::mitm::ResultShouldForwardToSession());
|
||||
R_UNLESS(is_hbl, sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
|
@ -85,18 +85,79 @@ namespace ams::mitm::fs {
|
|||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(&sd_fs.s)};
|
||||
std::unique_ptr<fs::fsa::IFileSystem> sd_ifs = std::make_unique<fs::RemoteFileSystem>(sd_fs);
|
||||
|
||||
out.SetValue(std::make_shared<IFileSystemInterface>(std::make_shared<fssystem::SubDirectoryFileSystem>(std::move(sd_ifs), AtmosphereHblWebContentDir), false), target_object_id);
|
||||
out.SetValue(std::make_shared<IFileSystemInterface>(std::make_shared<fs::ReadOnlyFileSystemAdapter>(std::make_unique<fssystem::SubDirectoryFileSystem>(std::move(sd_ifs), AtmosphereHblWebContentDir)), false), target_object_id);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result OpenProgramSpecificWebContentFileSystem(sf::Out<std::shared_ptr<IFileSystemInterface>> &out, ncm::ProgramId client_program_id, ncm::ProgramId program_id, FsFileSystemType filesystem_type, Service *fwd, const fssrv::sf::Path *path, bool with_id) {
|
||||
/* Directory must exist. */
|
||||
{
|
||||
FsDir d;
|
||||
R_UNLESS(R_SUCCEEDED(mitm::fs::OpenAtmosphereSdDirectory(&d, program_id, ProgramWebContentDir, fs::OpenDirectoryMode_Directory)), sm::mitm::ResultShouldForwardToSession());
|
||||
fsDirClose(&d);
|
||||
}
|
||||
|
||||
/* Open the SD card using fs.mitm's session. */
|
||||
FsFileSystem sd_fs;
|
||||
R_TRY(fsOpenSdCardFileSystem(&sd_fs));
|
||||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(&sd_fs.s)};
|
||||
std::unique_ptr<fs::fsa::IFileSystem> sd_ifs = std::make_unique<fs::RemoteFileSystem>(sd_fs);
|
||||
|
||||
/* Format the subdirectory path. */
|
||||
char program_web_content_path[fs::EntryNameLengthMax + 1];
|
||||
FormatAtmosphereSdPath(program_web_content_path, sizeof(program_web_content_path), program_id, ProgramWebContentDir);
|
||||
|
||||
/* Make a new filesystem. */
|
||||
{
|
||||
std::unique_ptr<fs::fsa::IFileSystem> subdir_fs = std::make_unique<fssystem::SubDirectoryFileSystem>(std::move(sd_ifs), program_web_content_path);
|
||||
std::shared_ptr<fs::fsa::IFileSystem> new_fs = nullptr;
|
||||
|
||||
/* Try to open the existing fs. */
|
||||
FsFileSystem base_fs;
|
||||
bool opened_base_fs = false;
|
||||
if (with_id) {
|
||||
opened_base_fs = R_SUCCEEDED(fsOpenFileSystemWithIdFwd(fwd, std::addressof(base_fs), static_cast<u64>(program_id), filesystem_type, path->str));
|
||||
} else {
|
||||
opened_base_fs = R_SUCCEEDED(fsOpenFileSystemWithPatchFwd(fwd, std::addressof(base_fs), static_cast<u64>(program_id), filesystem_type));
|
||||
}
|
||||
|
||||
if (opened_base_fs) {
|
||||
/* Create a layered adapter. */
|
||||
new_fs = std::make_shared<ReadOnlyLayeredFileSystem>(std::move(subdir_fs), std::make_unique<fs::RemoteFileSystem>(base_fs));
|
||||
} else {
|
||||
/* Without an existing FS, just make a read only adapter to the subdirectory. */
|
||||
new_fs = std::make_shared<fs::ReadOnlyFileSystemAdapter>(std::move(subdir_fs));
|
||||
}
|
||||
|
||||
out.SetValue(std::make_shared<IFileSystemInterface>(std::move(new_fs), false), target_object_id);
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result OpenWebContentFileSystem(sf::Out<std::shared_ptr<IFileSystemInterface>> &out, ncm::ProgramId client_program_id, ncm::ProgramId program_id, FsFileSystemType filesystem_type, Service *fwd, const fssrv::sf::Path *path, bool with_id, bool try_program_specific) {
|
||||
/* Check first that we're a web applet opening web content. */
|
||||
R_UNLESS(ncm::IsWebAppletProgramId(client_program_id), sm::mitm::ResultShouldForwardToSession());
|
||||
R_UNLESS(filesystem_type == FsFileSystemType_ContentManual, sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
/* Try to mount the HBL web filesystem. If this succeeds then we're done. */
|
||||
R_UNLESS(R_FAILED(OpenHblWebContentFileSystem(out, client_program_id, program_id, filesystem_type)), ResultSuccess());
|
||||
|
||||
/* If program specific override shouldn't be attempted, fall back. */
|
||||
R_UNLESS(try_program_specific, sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
/* If we're not opening a HBL filesystem, just try to open a generic one. */
|
||||
return OpenProgramSpecificWebContentFileSystem(out, client_program_id, program_id, filesystem_type, fwd, path, with_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Result FsMitmService::OpenFileSystemWithPatch(sf::Out<std::shared_ptr<IFileSystemInterface>> out, ncm::ProgramId program_id, u32 _filesystem_type) {
|
||||
return OpenHblWebContentFileSystem(out, this->client_info.program_id, program_id, static_cast<FsFileSystemType>(_filesystem_type));
|
||||
return OpenWebContentFileSystem(out, this->client_info.program_id, program_id, static_cast<FsFileSystemType>(_filesystem_type), this->forward_service.get(), nullptr, false, this->client_info.override_status.IsProgramSpecific());
|
||||
}
|
||||
|
||||
Result FsMitmService::OpenFileSystemWithId(sf::Out<std::shared_ptr<IFileSystemInterface>> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 _filesystem_type) {
|
||||
return OpenHblWebContentFileSystem(out, this->client_info.program_id, program_id, static_cast<FsFileSystemType>(_filesystem_type));
|
||||
return OpenWebContentFileSystem(out, this->client_info.program_id, program_id, static_cast<FsFileSystemType>(_filesystem_type), this->forward_service.get(), std::addressof(path), true, this->client_info.override_status.IsProgramSpecific());
|
||||
}
|
||||
|
||||
Result FsMitmService::OpenSdCardFileSystem(sf::Out<std::shared_ptr<IFileSystemInterface>> out) {
|
||||
|
|
|
@ -63,3 +63,29 @@ Result fsOpenSaveDataFileSystemFwd(Service* s, FsFileSystem* out, FsSaveDataSpac
|
|||
.out_objects = &out->s,
|
||||
);
|
||||
}
|
||||
|
||||
Result fsOpenFileSystemWithPatchFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType) {
|
||||
const struct {
|
||||
u32 fsType;
|
||||
u64 id;
|
||||
} in = { fsType, id };
|
||||
|
||||
return serviceDispatchIn(s, 7, in,
|
||||
.out_num_objects = 1,
|
||||
.out_objects = &out->s
|
||||
);
|
||||
}
|
||||
|
||||
Result fsOpenFileSystemWithIdFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType, const char* contentPath) {
|
||||
const struct {
|
||||
u32 fsType;
|
||||
u64 id;
|
||||
} in = { fsType, id };
|
||||
|
||||
return serviceDispatchIn(s, 8, in,
|
||||
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In },
|
||||
.buffers = { { contentPath, FS_MAX_PATH } },
|
||||
.out_num_objects = 1,
|
||||
.out_objects = &out->s
|
||||
);
|
||||
}
|
|
@ -19,6 +19,9 @@ Result fsOpenDataStorageByDataIdFwd(Service* s, FsStorage* out, u64 data_id, Ncm
|
|||
|
||||
Result fsOpenSaveDataFileSystemFwd(Service* s, FsFileSystem* out, FsSaveDataSpaceId save_data_space_id, const FsSaveDataAttribute *attr);
|
||||
|
||||
Result fsOpenFileSystemWithPatchFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType);
|
||||
Result fsOpenFileSystemWithIdFwd(Service* s, FsFileSystem* out, u64 id, FsFileSystemType fsType, const char* contentPath);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::mitm::fs {
|
||||
|
||||
class ReadOnlyLayeredFileSystem : public ams::fs::fsa::IFileSystem {
|
||||
private:
|
||||
ams::fs::ReadOnlyFileSystemAdapter fs_1;
|
||||
ams::fs::ReadOnlyFileSystemAdapter fs_2;
|
||||
public:
|
||||
explicit ReadOnlyLayeredFileSystem(std::unique_ptr<ams::fs::fsa::IFileSystem> a, std::unique_ptr<ams::fs::fsa::IFileSystem> b) : fs_1(std::move(a)), fs_2(std::move(b)) { /* ... */ }
|
||||
|
||||
virtual ~ReadOnlyLayeredFileSystem() { /* ... */ }
|
||||
private:
|
||||
virtual Result CreateFileImpl(const char *path, s64 size, int flags) override final {
|
||||
return ams::fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result DeleteFileImpl(const char *path) override final {
|
||||
return ams::fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result CreateDirectoryImpl(const char *path) override final {
|
||||
return ams::fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result DeleteDirectoryImpl(const char *path) override final {
|
||||
return ams::fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override final {
|
||||
return ams::fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result RenameFileImpl(const char *old_path, const char *new_path) override final {
|
||||
return ams::fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override final {
|
||||
return ams::fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result GetEntryTypeImpl(ams::fs::DirectoryEntryType *out, const char *path) override final {
|
||||
R_UNLESS(R_FAILED(this->fs_1.GetEntryType(out, path)), ResultSuccess());
|
||||
return this->fs_2.GetEntryType(out, path);
|
||||
}
|
||||
|
||||
virtual Result OpenFileImpl(std::unique_ptr<ams::fs::fsa::IFile> *out_file, const char *path, ams::fs::OpenMode mode) override final {
|
||||
R_UNLESS(R_FAILED(this->fs_1.OpenFile(out_file, path, mode)), ResultSuccess());
|
||||
return this->fs_2.OpenFile(out_file, path, mode);
|
||||
}
|
||||
|
||||
virtual Result OpenDirectoryImpl(std::unique_ptr<ams::fs::fsa::IDirectory> *out_dir, const char *path, ams::fs::OpenDirectoryMode mode) override final {
|
||||
R_UNLESS(R_FAILED(this->fs_1.OpenDirectory(out_dir, path, mode)), ResultSuccess());
|
||||
return this->fs_2.OpenDirectory(out_dir, path, mode);
|
||||
}
|
||||
|
||||
virtual Result CommitImpl() override final {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) {
|
||||
return ams::fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) {
|
||||
return ams::fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result CleanDirectoryRecursivelyImpl(const char *path) {
|
||||
return ams::fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result GetFileTimeStampRawImpl(ams::fs::FileTimeStampRaw *out, const char *path) {
|
||||
R_UNLESS(R_FAILED(this->fs_1.GetFileTimeStampRaw(out, path)), ResultSuccess());
|
||||
return this->fs_2.GetFileTimeStampRaw(out, path);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -114,7 +114,7 @@ namespace ams::mitm::fs {
|
|||
os::Mutex g_fs_romfs_path_lock;
|
||||
char g_fs_romfs_path_buffer[fs::EntryNameLengthMax + 1];
|
||||
|
||||
__attribute__((noinline)) void OpenFileSystemRomfsDirectory(FsDir *out, ncm::ProgramId program_id, BuildDirectoryContext *parent, fs::OpenDirectoryMode mode, FsFileSystem *fs) {
|
||||
NOINLINE void OpenFileSystemRomfsDirectory(FsDir *out, ncm::ProgramId program_id, BuildDirectoryContext *parent, fs::OpenDirectoryMode mode, FsFileSystem *fs) {
|
||||
std::scoped_lock lk(g_fs_romfs_path_lock);
|
||||
parent->GetPath(g_fs_romfs_path_buffer);
|
||||
R_ABORT_UNLESS(mitm::fs::OpenAtmosphereRomfsDirectory(out, program_id, g_fs_romfs_path_buffer, mode, fs));
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace ams::pm::resource {
|
|||
constexpr size_t ExtraSystemEventCount600 = 100;
|
||||
constexpr size_t ExtraSystemSessionCount600 = 100;
|
||||
constexpr size_t ReservedMemorySize600 = 5_MB;
|
||||
constexpr size_t ExtraSystemSessionCount920 = 33;
|
||||
|
||||
/* Atmosphere always allocates extra memory for system usage. */
|
||||
constexpr size_t ExtraSystemMemorySizeAtmosphere = 24_MB;
|
||||
|
@ -205,6 +206,12 @@ namespace ams::pm::resource {
|
|||
g_resource_limits[ResourceLimitGroup_System][LimitableResource_Events] += ExtraSystemEventCount600;
|
||||
g_resource_limits[ResourceLimitGroup_System][LimitableResource_Sessions] += ExtraSystemSessionCount600;
|
||||
}
|
||||
if (hos_version >= hos::Version_900) {
|
||||
/* 9.2.0 increased the system session limit. */
|
||||
/* NOTE: We don't currently support detection of minor version, so we will provide this increase on 9.0.0+. */
|
||||
/* This shouldn't impact any existing behavior in undesirable ways. */
|
||||
g_resource_limits[ResourceLimitGroup_System][LimitableResource_Sessions] += ExtraSystemSessionCount920;
|
||||
}
|
||||
|
||||
/* 7.0.0+: Calculate the number of extra application threads available. */
|
||||
if (hos::GetVersion() >= hos::Version_700) {
|
||||
|
|
Loading…
Add table
Reference in a new issue