fs.mitm: implement layered html redirection (closes #814)

This commit is contained in:
Michael Scire
2020-02-25 16:44:36 -08:00
parent 8da705d40b
commit dc1404061c
7 changed files with 343 additions and 20 deletions

View File

@@ -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 {
@@ -84,11 +85,11 @@ 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) {
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;
@@ -106,12 +107,35 @@ namespace ams::mitm::fs {
char program_web_content_path[fs::EntryNameLengthMax + 1];
FormatAtmosphereSdPath(program_web_content_path, sizeof(program_web_content_path), program_id, ProgramWebContentDir);
/* Set the output directory. */
out.SetValue(std::make_shared<IFileSystemInterface>(std::make_shared<fssystem::SubDirectoryFileSystem>(std::move(sd_ifs), program_web_content_path), false), target_object_id);
/* 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) {
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());
@@ -119,18 +143,21 @@ namespace ams::mitm::fs {
/* 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);
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 OpenWebContentFileSystem(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 OpenWebContentFileSystem(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) {

View File

@@ -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
);
}

View File

@@ -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
}

View File

@@ -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);
}
};
}