mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-27 12:46:03 +00:00
fs.mitm: add Nintendo directory redirection code
This commit is contained in:
parent
cb532e3fb3
commit
4dac80df75
5 changed files with 401 additions and 1 deletions
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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/>.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "../utils.hpp"
|
||||
#include "fs_directory_redirection_filesystem.hpp"
|
||||
#include "fs_path_utils.hpp"
|
||||
|
||||
static char *GetNormalizedDirectory(const char *dir_prefix) {
|
||||
/* Normalize the path. */
|
||||
char normal_path[FS_MAX_PATH + 1];
|
||||
size_t normal_path_len;
|
||||
Result rc = FsPathUtils::Normalize(normal_path, sizeof(normal_path), dir_prefix, &normal_path_len);
|
||||
if (R_FAILED(rc)) {
|
||||
/* N calls svcBreak here. */
|
||||
std::abort();
|
||||
}
|
||||
|
||||
/* Ensure terminating '/' */
|
||||
if (normal_path[normal_path_len-1] != '/') {
|
||||
if (normal_path_len + 2 > sizeof(normal_path)) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
strncat(normal_path, "/", 2);
|
||||
normal_path[sizeof(normal_path)-1] = 0;
|
||||
normal_path_len++;
|
||||
}
|
||||
|
||||
char *output = static_cast<char *>(malloc(normal_path_len + 1));
|
||||
if (output == nullptr) {
|
||||
std::abort();
|
||||
/* TODO: Result error code? */
|
||||
}
|
||||
|
||||
std::strncpy(output, normal_path, normal_path_len + 1);
|
||||
output[normal_path_len] = 0;
|
||||
return output;
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::Initialize(const char *before, const char *after) {
|
||||
if (strnlen(before, FS_MAX_PATH) >= FS_MAX_PATH || strnlen(after, FS_MAX_PATH) >= FS_MAX_PATH) {
|
||||
return ResultFsTooLongPath;
|
||||
}
|
||||
|
||||
this->before_dir = GetNormalizedDirectory(before);
|
||||
this->after_dir = GetNormalizedDirectory(after);
|
||||
this->before_dir_len = strlen(this->before_dir);
|
||||
this->after_dir_len = strlen(this->after_dir);
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::GetFullPath(char *out, size_t out_size, const char *relative_path) {
|
||||
FsPath tmp_rel_path;
|
||||
Result rc = 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 (this->after_dir_len + strnlen(tmp_rel_path.str, FS_MAX_PATH) - this->before_dir_len > out_size) {
|
||||
return ResultFsTooLongPath;
|
||||
}
|
||||
|
||||
/* Copy after path. */
|
||||
std::strncpy(out, this->after_dir, out_size);
|
||||
out[out_size - 1] = 0;
|
||||
|
||||
/* Normalize it. */
|
||||
return FsPathUtils::Normalize(out + this->after_dir_len - 1, out_size - (this->after_dir_len - 1), relative_path + this->before_dir_len - 1, nullptr);
|
||||
} else if (std::memcmp(tmp_rel_path.str, this->before_dir, this->before_dir_len - 1) == 0) {
|
||||
/* Handling raw directory. */
|
||||
if (this->after_dir_len + 1 > out_size) {
|
||||
return ResultFsTooLongPath;
|
||||
}
|
||||
std::strncpy(out, this->after_dir, out_size);
|
||||
out[out_size - 1] = 0;
|
||||
return ResultSuccess;
|
||||
} else {
|
||||
return FsPathUtils::Normalize(out, out_size, relative_path, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::CreateFileImpl(const FsPath &path, uint64_t size, int flags) {
|
||||
Result rc;
|
||||
FsPath full_path;
|
||||
|
||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return this->base_fs->CreateFile(full_path, size, flags);
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::DeleteFileImpl(const FsPath &path) {
|
||||
Result rc;
|
||||
FsPath full_path;
|
||||
|
||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return this->base_fs->DeleteFile(full_path);
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::CreateDirectoryImpl(const FsPath &path) {
|
||||
Result rc;
|
||||
FsPath full_path;
|
||||
|
||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return this->base_fs->CreateDirectory(full_path);
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::DeleteDirectoryImpl(const FsPath &path) {
|
||||
Result rc;
|
||||
FsPath full_path;
|
||||
|
||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return this->base_fs->DeleteDirectory(full_path);
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::DeleteDirectoryRecursivelyImpl(const FsPath &path) {
|
||||
Result rc;
|
||||
FsPath full_path;
|
||||
|
||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return this->base_fs->DeleteDirectoryRecursively(full_path);
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::RenameFileImpl(const FsPath &old_path, const FsPath &new_path) {
|
||||
Result rc;
|
||||
FsPath full_old_path, full_new_path;
|
||||
|
||||
if (R_FAILED((rc = GetFullPath(full_old_path, old_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);
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) {
|
||||
Result rc;
|
||||
FsPath full_old_path, full_new_path;
|
||||
|
||||
if (R_FAILED((rc = GetFullPath(full_old_path, old_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);
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) {
|
||||
Result rc;
|
||||
FsPath full_path;
|
||||
|
||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return this->base_fs->GetEntryType(out, full_path);
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::OpenFileImpl(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) {
|
||||
Result rc;
|
||||
FsPath full_path;
|
||||
|
||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
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 rc;
|
||||
FsPath full_path;
|
||||
|
||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return this->base_fs->OpenDirectory(out_dir, full_path, mode);
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::CommitImpl() {
|
||||
return this->base_fs->Commit();
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) {
|
||||
Result rc;
|
||||
FsPath full_path;
|
||||
|
||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return this->base_fs->GetFreeSpaceSize(out, full_path);
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) {
|
||||
Result rc;
|
||||
FsPath full_path;
|
||||
|
||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return this->base_fs->GetTotalSpaceSize(out, full_path);
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::CleanDirectoryRecursivelyImpl(const FsPath &path) {
|
||||
Result rc;
|
||||
FsPath full_path;
|
||||
|
||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return this->base_fs->CleanDirectoryRecursively(full_path);
|
||||
}
|
||||
|
||||
Result DirectoryRedirectionFileSystem::GetFileTimeStampRawImpl(FsTimeStampRaw *out, const FsPath &path) {
|
||||
Result rc;
|
||||
FsPath full_path;
|
||||
|
||||
if (R_FAILED((rc = GetFullPath(full_path, path)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
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 rc;
|
||||
FsPath full_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);
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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 <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "fs_ifilesystem.hpp"
|
||||
#include "fs_path_utils.hpp"
|
||||
|
||||
class DirectoryRedirectionFileSystem : public IFileSystem {
|
||||
private:
|
||||
std::shared_ptr<IFileSystem> base_fs;
|
||||
char *before_dir = nullptr;
|
||||
size_t before_dir_len = 0;
|
||||
char *after_dir = nullptr;
|
||||
size_t after_dir_len = 0;
|
||||
|
||||
public:
|
||||
DirectoryRedirectionFileSystem(IFileSystem *fs, const char *before, const char *after) : base_fs(fs) {
|
||||
Result rc = 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) {
|
||||
Result rc = this->Initialize(before, after);
|
||||
if (R_FAILED(rc)) {
|
||||
fatalSimple(rc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual ~DirectoryRedirectionFileSystem() {
|
||||
if (this->before_dir != nullptr) {
|
||||
free(this->before_dir);
|
||||
}
|
||||
if (this->after_dir != nullptr) {
|
||||
free(this->after_dir);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Result Initialize(const char *before, const char *after);
|
||||
protected:
|
||||
Result GetFullPath(char *out, size_t out_size, const char *relative_path);
|
||||
Result GetFullPath(FsPath &full_path, const FsPath &relative_path) {
|
||||
return GetFullPath(full_path.str, sizeof(full_path.str), relative_path.str);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual Result CreateFileImpl(const FsPath &path, uint64_t size, int flags) override;
|
||||
virtual Result DeleteFileImpl(const FsPath &path) override;
|
||||
virtual Result CreateDirectoryImpl(const FsPath &path) override;
|
||||
virtual Result DeleteDirectoryImpl(const FsPath &path) override;
|
||||
virtual Result DeleteDirectoryRecursivelyImpl(const FsPath &path) override;
|
||||
virtual Result RenameFileImpl(const FsPath &old_path, const FsPath &new_path) override;
|
||||
virtual Result RenameDirectoryImpl(const FsPath &old_path, const FsPath &new_path) override;
|
||||
virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const FsPath &path) override;
|
||||
virtual Result OpenFileImpl(std::unique_ptr<IFile> &out_file, const FsPath &path, OpenMode mode) override;
|
||||
virtual Result OpenDirectoryImpl(std::unique_ptr<IDirectory> &out_dir, const FsPath &path, DirectoryOpenMode mode) override;
|
||||
virtual Result CommitImpl() override;
|
||||
virtual Result GetFreeSpaceSizeImpl(uint64_t *out, const FsPath &path) override;
|
||||
virtual Result GetTotalSpaceSizeImpl(uint64_t *out, const FsPath &path) override;
|
||||
virtual Result CleanDirectoryRecursivelyImpl(const FsPath &path) override;
|
||||
virtual Result GetFileTimeStampRawImpl(FsTimeStampRaw *out, const FsPath &path) override;
|
||||
virtual Result QueryEntryImpl(char *out, uint64_t out_size, const char *in, uint64_t in_size, int query, const FsPath &path) override;
|
||||
};
|
|
@ -31,6 +31,7 @@
|
|||
#include "fs_dir_utils.hpp"
|
||||
#include "fs_save_utils.hpp"
|
||||
#include "fs_subdirectory_filesystem.hpp"
|
||||
#include "fs_directory_redirection_filesystem.hpp"
|
||||
#include "fs_directory_savedata_filesystem.hpp"
|
||||
|
||||
#include "../debug.hpp"
|
||||
|
@ -161,6 +162,43 @@ Result FsMitmService::OpenFileSystemWithId(Out<std::shared_ptr<IFileSystemInterf
|
|||
return this->OpenHblWebContentFileSystem(out_fs);
|
||||
}
|
||||
|
||||
Result FsMitmService::OpenSdCardFileSystem(Out<std::shared_ptr<IFileSystemInterface>> out_fs) {
|
||||
/* We only care about redirecting this for NS/Emunand. */
|
||||
if (!IsEmunand()) {
|
||||
return ResultAtmosphereMitmShouldForwardToSession;
|
||||
}
|
||||
if (this->title_id != TitleId_Ns) {
|
||||
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. */
|
||||
FsFileSystem sd_fs;
|
||||
if (R_FAILED((rc = fsMountSdcard(&sd_fs)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
std::shared_ptr<IFileSystem> redir_fs = std::make_shared<DirectoryRedirectionFileSystem>(new ProxyFileSystem(sd_fs), "/Nintendo", "/Emu/0000" /* TODO: Real Path */);
|
||||
fs = std::make_shared<IFileSystemInterface>(redir_fs);
|
||||
if (out_fs.IsDomain()) {
|
||||
out_domain_id = sd_fs.s.object_id;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result FsMitmService::OpenSaveDataFileSystem(Out<std::shared_ptr<IFileSystemInterface>> out_fs, u8 space_id, FsSave save_struct) {
|
||||
bool should_redirect_saves = false;
|
||||
const bool has_redirect_save_flags = Utils::HasFlag(this->title_id, "redirect_save");
|
||||
|
|
|
@ -29,6 +29,8 @@ enum FspSrvCmd : u32 {
|
|||
FspSrvCmd_OpenFileSystemWithPatch = 7,
|
||||
FspSrvCmd_OpenFileSystemWithId = 8,
|
||||
|
||||
FspSrvCmd_OpenSdCardFileSystem = 18,
|
||||
|
||||
FspSrvCmd_OpenSaveDataFileSystem = 51,
|
||||
|
||||
FspSrvCmd_OpenBisStorage = 12,
|
||||
|
@ -75,6 +77,7 @@ class FsMitmService : public IMitmServiceObject {
|
|||
/* Overridden commands. */
|
||||
Result OpenFileSystemWithPatch(Out<std::shared_ptr<IFileSystemInterface>> out, u64 title_id, u32 filesystem_type);
|
||||
Result OpenFileSystemWithId(Out<std::shared_ptr<IFileSystemInterface>> out, InPointer<char> path, u64 title_id, u32 filesystem_type);
|
||||
Result OpenSdCardFileSystem(Out<std::shared_ptr<IFileSystemInterface>> out);
|
||||
Result OpenSaveDataFileSystem(Out<std::shared_ptr<IFileSystemInterface>> out, u8 space_id, FsSave save_struct);
|
||||
Result OpenBisStorage(Out<std::shared_ptr<IStorageInterface>> out, u32 bis_partition_id);
|
||||
Result OpenDataStorageByCurrentProcess(Out<std::shared_ptr<IStorageInterface>> out);
|
||||
|
@ -84,6 +87,7 @@ class FsMitmService : public IMitmServiceObject {
|
|||
/* TODO MakeServiceCommandMeta<FspSrvCmd_OpenFileSystemDeprecated, &FsMitmService::OpenFileSystemDeprecated>(), */
|
||||
MakeServiceCommandMeta<FspSrvCmd_OpenFileSystemWithPatch, &FsMitmService::OpenFileSystemWithPatch, FirmwareVersion_200>(),
|
||||
MakeServiceCommandMeta<FspSrvCmd_OpenFileSystemWithId, &FsMitmService::OpenFileSystemWithId, FirmwareVersion_200>(),
|
||||
MakeServiceCommandMeta<FspSrvCmd_OpenSdCardFileSystem, &FsMitmService::OpenSdCardFileSystem>(),
|
||||
MakeServiceCommandMeta<FspSrvCmd_OpenSaveDataFileSystem, &FsMitmService::OpenSaveDataFileSystem>(),
|
||||
MakeServiceCommandMeta<FspSrvCmd_OpenBisStorage, &FsMitmService::OpenBisStorage>(),
|
||||
MakeServiceCommandMeta<FspSrvCmd_OpenDataStorageByCurrentProcess, &FsMitmService::OpenDataStorageByCurrentProcess>(),
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 8f2328975a66519275ada907cbc0000377ce5ede
|
||||
Subproject commit 44f52b445e9154a18fc0e99b9efc6be78b859495
|
Loading…
Reference in a new issue