fs.mitm: implement layered html redirection (closes #814)
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user