Revert "hoc-clk: add live vdd2, live boost clock and basic pwm dimming"

This reverts commit 15b7df8ef1.
This commit is contained in:
souldbminersmwc
2025-11-09 16:14:52 -05:00
parent 22ec140738
commit 21a3f953d7
3804 changed files with 435 additions and 570162 deletions

View File

@@ -1,549 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
namespace ams::fs {
s64 HierarchicalRomFileTable::QueryDirectoryEntryBucketStorageSize(StorageSizeType count) {
return DirectoryEntryMapTable::QueryBucketStorageSize(count);
}
s64 HierarchicalRomFileTable::QueryDirectoryEntrySize(StorageSizeType aux_size) {
return DirectoryEntryMapTable::QueryEntrySize(aux_size);
}
s64 HierarchicalRomFileTable::QueryFileEntryBucketStorageSize(StorageSizeType count) {
return FileEntryMapTable::QueryBucketStorageSize(count);
}
s64 HierarchicalRomFileTable::QueryFileEntrySize(StorageSizeType aux_size) {
return FileEntryMapTable::QueryEntrySize(aux_size);
}
Result HierarchicalRomFileTable::Format(SubStorage dir_bucket, SubStorage file_bucket) {
s64 dir_bucket_size;
R_TRY(dir_bucket.GetSize(std::addressof(dir_bucket_size)));
R_TRY(DirectoryEntryMapTable::Format(dir_bucket, DirectoryEntryMapTable::QueryBucketCount(dir_bucket_size)));
s64 file_bucket_size;
R_TRY(file_bucket.GetSize(std::addressof(file_bucket_size)));
R_TRY(FileEntryMapTable::Format(file_bucket, FileEntryMapTable::QueryBucketCount(file_bucket_size)));
R_SUCCEED();
}
HierarchicalRomFileTable::HierarchicalRomFileTable() { /* ... */ }
Result HierarchicalRomFileTable::Initialize(SubStorage dir_bucket, SubStorage dir_entry, SubStorage file_bucket, SubStorage file_entry) {
s64 dir_bucket_size;
R_TRY(dir_bucket.GetSize(std::addressof(dir_bucket_size)));
R_TRY(m_dir_table.Initialize(dir_bucket, DirectoryEntryMapTable::QueryBucketCount(dir_bucket_size), dir_entry));
s64 file_bucket_size;
R_TRY(file_bucket.GetSize(std::addressof(file_bucket_size)));
R_TRY(m_file_table.Initialize(file_bucket, FileEntryMapTable::QueryBucketCount(file_bucket_size), file_entry));
R_SUCCEED();
}
void HierarchicalRomFileTable::Finalize() {
m_dir_table.Finalize();
m_file_table.Finalize();
}
Result HierarchicalRomFileTable::CreateRootDirectory() {
Position root_pos = RootPosition;
EntryKey root_key = {};
root_key.key.parent = root_pos;
RomDirectoryEntry root_entry = {
.next = InvalidPosition,
.dir = InvalidPosition,
.file = InvalidPosition,
};
R_RETURN(m_dir_table.Add(std::addressof(root_pos), root_key, root_entry));
}
Result HierarchicalRomFileTable::CreateDirectory(RomDirectoryId *out, const RomPathChar *path) {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(path != nullptr);
RomDirectoryEntry parent_entry = {};
EntryKey new_key = {};
R_TRY(this->FindDirectoryRecursive(std::addressof(new_key), std::addressof(parent_entry), path));
R_TRY(this->CheckSameEntryExists(new_key, fs::ResultDbmAlreadyExists()));
RomDirectoryEntry new_entry = {
.next = InvalidPosition,
.dir = InvalidPosition,
.file = InvalidPosition,
};
Position new_pos = 0;
R_TRY_CATCH(m_dir_table.Add(std::addressof(new_pos), new_key, new_entry)) {
R_CONVERT(fs::ResultDbmKeyFull, fs::ResultDbmDirectoryEntryFull())
} R_END_TRY_CATCH;
*out = PositionToDirectoryId(new_pos);
if (parent_entry.dir == InvalidPosition) {
parent_entry.dir = new_pos;
R_TRY(m_dir_table.SetByPosition(new_key.key.parent, parent_entry));
} else {
Position cur_pos = parent_entry.dir;
while (true) {
RomEntryKey cur_key = {};
RomDirectoryEntry cur_entry = {};
R_TRY(m_dir_table.GetByPosition(std::addressof(cur_key), std::addressof(cur_entry), cur_pos));
if (cur_entry.next == InvalidPosition) {
cur_entry.next = new_pos;
R_TRY(m_dir_table.SetByPosition(cur_pos, cur_entry));
break;
}
cur_pos = cur_entry.next;
}
}
R_SUCCEED();
}
Result HierarchicalRomFileTable::CreateFile(RomFileId *out, const RomPathChar *path, const FileInfo &info) {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(path != nullptr);
RomDirectoryEntry parent_entry = {};
EntryKey new_key = {};
R_TRY(this->FindFileRecursive(std::addressof(new_key), std::addressof(parent_entry), path));
R_TRY(this->CheckSameEntryExists(new_key, fs::ResultDbmAlreadyExists()));
RomFileEntry new_entry = {
.next = InvalidPosition,
.info = info,
};
Position new_pos = 0;
R_TRY_CATCH(m_file_table.Add(std::addressof(new_pos), new_key, new_entry)) {
R_CONVERT(fs::ResultDbmKeyFull, fs::ResultDbmFileEntryFull())
} R_END_TRY_CATCH;
*out = PositionToFileId(new_pos);
if (parent_entry.file == InvalidPosition) {
parent_entry.file = new_pos;
R_TRY(m_dir_table.SetByPosition(new_key.key.parent, parent_entry));
} else {
Position cur_pos = parent_entry.file;
while (true) {
RomEntryKey cur_key = {};
RomFileEntry cur_entry = {};
R_TRY(m_file_table.GetByPosition(std::addressof(cur_key), std::addressof(cur_entry), cur_pos));
if (cur_entry.next == InvalidPosition) {
cur_entry.next = new_pos;
R_TRY(m_file_table.SetByPosition(cur_pos, cur_entry));
break;
}
cur_pos = cur_entry.next;
}
}
R_SUCCEED();
}
Result HierarchicalRomFileTable::ConvertPathToDirectoryId(RomDirectoryId *out, const RomPathChar *path) {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(path != nullptr);
RomDirectoryEntry parent_entry = {};
EntryKey key = {};
R_TRY(this->FindDirectoryRecursive(std::addressof(key), std::addressof(parent_entry), path));
Position pos = 0;
RomDirectoryEntry entry = {};
R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key));
*out = PositionToDirectoryId(pos);
R_SUCCEED();
}
Result HierarchicalRomFileTable::ConvertPathToFileId(RomFileId *out, const RomPathChar *path) {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(path != nullptr);
RomDirectoryEntry parent_entry = {};
EntryKey key = {};
R_TRY(this->FindDirectoryRecursive(std::addressof(key), std::addressof(parent_entry), path));
Position pos = 0;
RomFileEntry entry = {};
R_TRY(this->GetFileEntry(std::addressof(pos), std::addressof(entry), key));
*out = PositionToFileId(pos);
R_SUCCEED();
}
Result HierarchicalRomFileTable::OpenFile(FileInfo *out, const RomPathChar *path) {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(path != nullptr);
RomDirectoryEntry parent_entry = {};
EntryKey key = {};
R_TRY(this->FindFileRecursive(std::addressof(key), std::addressof(parent_entry), path));
R_RETURN(this->OpenFile(out, key));
}
Result HierarchicalRomFileTable::OpenFile(FileInfo *out, RomFileId id) {
AMS_ASSERT(out != nullptr);
RomFileEntry entry = {};
R_TRY(this->GetFileEntry(std::addressof(entry), id));
*out = entry.info;
R_SUCCEED();
}
Result HierarchicalRomFileTable::FindOpen(FindPosition *out, const RomPathChar *path) {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(path != nullptr);
RomDirectoryEntry parent_entry = {};
EntryKey key = {};
R_TRY(this->FindDirectoryRecursive(std::addressof(key), std::addressof(parent_entry), path));
R_RETURN(this->FindOpen(out, key));
}
Result HierarchicalRomFileTable::FindOpen(FindPosition *out, RomDirectoryId id) {
AMS_ASSERT(out != nullptr);
out->next_dir = InvalidPosition;
out->next_file = InvalidPosition;
RomDirectoryEntry entry = {};
R_TRY(this->GetDirectoryEntry(std::addressof(entry), id));
out->next_dir = entry.dir;
out->next_file = entry.file;
R_SUCCEED();
}
Result HierarchicalRomFileTable::FindNextDirectory(RomPathChar *out, FindPosition *find, size_t length) {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(find != nullptr);
AMS_ASSERT(length > RomPathTool::MaxPathLength);
AMS_UNUSED(length);
R_UNLESS(find->next_dir != InvalidPosition, fs::ResultDbmFindFinished());
RomEntryKey key = {};
RomDirectoryEntry entry = {};
size_t aux_size = 0;
R_TRY(m_dir_table.GetByPosition(std::addressof(key), std::addressof(entry), out, std::addressof(aux_size), find->next_dir));
AMS_ASSERT(aux_size / sizeof(RomPathChar) <= RomPathTool::MaxPathLength);
out[aux_size / sizeof(RomPathChar)] = RomStringTraits::NullTerminator;
find->next_dir = entry.next;
R_SUCCEED();
}
Result HierarchicalRomFileTable::FindNextFile(RomPathChar *out, FindPosition *find, size_t length) {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(find != nullptr);
AMS_ASSERT(length > RomPathTool::MaxPathLength);
AMS_UNUSED(length);
R_UNLESS(find->next_file != InvalidPosition, fs::ResultDbmFindFinished());
RomEntryKey key = {};
RomFileEntry entry = {};
size_t aux_size = 0;
R_TRY(m_file_table.GetByPosition(std::addressof(key), std::addressof(entry), out, std::addressof(aux_size), find->next_file));
AMS_ASSERT(aux_size / sizeof(RomPathChar) <= RomPathTool::MaxPathLength);
out[aux_size / sizeof(RomPathChar)] = RomStringTraits::NullTerminator;
find->next_file = entry.next;
R_SUCCEED();
}
Result HierarchicalRomFileTable::QueryRomFileSystemSize(s64 *out_dir_entry_size, s64 *out_file_entry_size) {
AMS_ASSERT(out_dir_entry_size != nullptr);
AMS_ASSERT(out_file_entry_size != nullptr);
*out_dir_entry_size = m_dir_table.GetTotalEntrySize();
*out_file_entry_size = m_file_table.GetTotalEntrySize();
R_SUCCEED();
}
Result HierarchicalRomFileTable::GetParent(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, Position pos, RomPathTool::RomEntryName name, const RomPathChar *path) {
AMS_ASSERT(out_pos != nullptr);
AMS_ASSERT(out_dir_key != nullptr);
AMS_ASSERT(out_dir_entry != nullptr);
AMS_ASSERT(path != nullptr);
RomEntryKey p_key = {};
RomDirectoryEntry p_entry = {};
R_TRY(m_dir_table.GetByPosition(std::addressof(p_key), std::addressof(p_entry), pos));
out_dir_key->key = p_key;
R_TRY(RomPathTool::GetParentDirectoryName(std::addressof(out_dir_key->name), name, path));
R_TRY(this->GetDirectoryEntry(out_pos, out_dir_entry, *out_dir_key));
R_SUCCEED();
}
Result HierarchicalRomFileTable::FindParentDirectoryRecursive(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, RomPathTool::PathParser *parser, const RomPathChar *path) {
AMS_ASSERT(out_pos != nullptr);
AMS_ASSERT(out_dir_key != nullptr);
AMS_ASSERT(out_dir_entry != nullptr);
AMS_ASSERT(parser != nullptr);
AMS_ASSERT(path != nullptr);
Position dir_pos = RootPosition;
EntryKey dir_key = {};
RomDirectoryEntry dir_entry = {};
dir_key.key.parent = RootPosition;
R_TRY(parser->GetNextDirectoryName(std::addressof(dir_key.name)));
R_TRY(this->GetDirectoryEntry(std::addressof(dir_pos), std::addressof(dir_entry), dir_key));
Position parent_pos = dir_pos;
while (!parser->IsParseFinished()) {
EntryKey old_key = dir_key;
R_TRY(parser->GetNextDirectoryName(std::addressof(dir_key.name)));
if (dir_key.name.IsCurrentDirectory()) {
dir_key = old_key;
continue;
} else if (dir_key.name.IsParentDirectory()) {
R_UNLESS(parent_pos != RootPosition, fs::ResultDirectoryUnobtainable());
R_TRY(this->GetParent(std::addressof(parent_pos), std::addressof(dir_key), std::addressof(dir_entry), dir_key.key.parent, dir_key.name, path));
} else {
dir_key.key.parent = parent_pos;
R_TRY_CATCH(this->GetDirectoryEntry(std::addressof(dir_pos), std::addressof(dir_entry), dir_key)) {
R_CONVERT(fs::ResultDbmInvalidOperation, fs::ResultDbmNotFound())
} R_END_TRY_CATCH;
parent_pos = dir_pos;
}
}
*out_pos = parent_pos;
*out_dir_key = dir_key;
*out_dir_entry = dir_entry;
R_SUCCEED();
}
Result HierarchicalRomFileTable::FindPathRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, bool is_dir, const RomPathChar *path) {
AMS_ASSERT(out_key != nullptr);
AMS_ASSERT(out_dir_entry != nullptr);
AMS_ASSERT(path != nullptr);
RomPathTool::PathParser parser;
R_TRY(parser.Initialize(path));
EntryKey parent_key = {};
Position parent_pos = 0;
R_TRY(this->FindParentDirectoryRecursive(std::addressof(parent_pos), std::addressof(parent_key), out_dir_entry, std::addressof(parser), path));
if (is_dir) {
RomPathTool::RomEntryName name = {};
R_TRY(parser.GetAsDirectoryName(std::addressof(name)));
if (name.IsCurrentDirectory()) {
*out_key = parent_key;
if (out_key->key.parent != RootPosition) {
Position pos = 0;
R_TRY(this->GetParent(std::addressof(pos), std::addressof(parent_key), out_dir_entry, out_key->key.parent, out_key->name, path));
}
} else if (name.IsParentDirectory()) {
R_UNLESS(parent_pos != RootPosition, fs::ResultDirectoryUnobtainable());
Position pos = 0;
RomDirectoryEntry cur_entry = {};
R_TRY(this->GetParent(std::addressof(pos), out_key, std::addressof(cur_entry), parent_key.key.parent, parent_key.name, path));
if (out_key->key.parent != RootPosition) {
R_TRY(this->GetParent(std::addressof(pos), std::addressof(parent_key), out_dir_entry, out_key->key.parent, out_key->name, path));
}
} else {
out_key->name = name;
out_key->key.parent = out_key->name.IsRootDirectory() ? RootPosition : parent_pos;
}
} else {
{
RomPathTool::RomEntryName name = {};
R_TRY(parser.GetAsDirectoryName(std::addressof(name)));
R_UNLESS(!name.IsParentDirectory() || parent_pos != RootPosition, fs::ResultDirectoryUnobtainable());
}
R_UNLESS(!parser.IsDirectoryPath(), fs::ResultDbmInvalidOperation());
out_key->key.parent = parent_pos;
R_TRY(parser.GetAsFileName(std::addressof(out_key->name)));
}
R_SUCCEED();
}
Result HierarchicalRomFileTable::FindDirectoryRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, const RomPathChar *path) {
AMS_ASSERT(out_key != nullptr);
AMS_ASSERT(out_dir_entry != nullptr);
AMS_ASSERT(path != nullptr);
R_RETURN(this->FindPathRecursive(out_key, out_dir_entry, true, path));
}
Result HierarchicalRomFileTable::FindFileRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, const RomPathChar *path) {
AMS_ASSERT(out_key != nullptr);
AMS_ASSERT(out_dir_entry != nullptr);
AMS_ASSERT(path != nullptr);
R_RETURN(this->FindPathRecursive(out_key, out_dir_entry, false, path));
}
Result HierarchicalRomFileTable::CheckSameEntryExists(const EntryKey &key, Result if_exists) {
/* Check dir */
{
Position pos = InvalidPosition;
RomDirectoryEntry entry = {};
const Result get_res = m_dir_table.Get(std::addressof(pos), std::addressof(entry), key);
if (!fs::ResultDbmKeyNotFound::Includes(get_res)) {
R_TRY(get_res);
R_THROW(if_exists);
}
}
/* Check file */
{
Position pos = InvalidPosition;
RomFileEntry entry = {};
const Result get_res = m_file_table.Get(std::addressof(pos), std::addressof(entry), key);
if (!fs::ResultDbmKeyNotFound::Includes(get_res)) {
R_TRY(get_res);
R_THROW(if_exists);
}
}
R_SUCCEED();
}
Result HierarchicalRomFileTable::GetDirectoryEntry(Position *out_pos, RomDirectoryEntry *out_entry, const EntryKey &key) {
AMS_ASSERT(out_pos != nullptr);
AMS_ASSERT(out_entry != nullptr);
const Result dir_res = m_dir_table.Get(out_pos, out_entry, key);
R_UNLESS(R_FAILED(dir_res), dir_res);
R_UNLESS(fs::ResultDbmKeyNotFound::Includes(dir_res), dir_res);
Position pos = 0;
RomFileEntry entry = {};
const Result file_res = m_file_table.Get(std::addressof(pos), std::addressof(entry), key);
R_UNLESS(R_FAILED(file_res), fs::ResultDbmInvalidOperation());
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), fs::ResultDbmDirectoryNotFound());
R_RETURN(file_res);
}
Result HierarchicalRomFileTable::GetDirectoryEntry(RomDirectoryEntry *out_entry, RomDirectoryId id) {
AMS_ASSERT(out_entry != nullptr);
Position pos = DirectoryIdToPosition(id);
RomEntryKey key = {};
const Result dir_res = m_dir_table.GetByPosition(std::addressof(key), out_entry, pos);
R_UNLESS(R_FAILED(dir_res), dir_res);
R_UNLESS(fs::ResultDbmKeyNotFound::Includes(dir_res), dir_res);
RomFileEntry entry = {};
const Result file_res = m_file_table.GetByPosition(std::addressof(key), std::addressof(entry), pos);
R_UNLESS(R_FAILED(file_res), fs::ResultDbmInvalidOperation());
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), fs::ResultDbmDirectoryNotFound());
R_RETURN(file_res);
}
Result HierarchicalRomFileTable::GetFileEntry(Position *out_pos, RomFileEntry *out_entry, const EntryKey &key) {
AMS_ASSERT(out_pos != nullptr);
AMS_ASSERT(out_entry != nullptr);
const Result file_res = m_file_table.Get(out_pos, out_entry, key);
R_UNLESS(R_FAILED(file_res), file_res);
R_UNLESS(fs::ResultDbmKeyNotFound::Includes(file_res), file_res);
Position pos = 0;
RomDirectoryEntry entry = {};
const Result dir_res = m_dir_table.Get(std::addressof(pos), std::addressof(entry), key);
R_UNLESS(R_FAILED(dir_res), fs::ResultDbmInvalidOperation());
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), fs::ResultDbmFileNotFound());
R_RETURN(dir_res);
}
Result HierarchicalRomFileTable::GetFileEntry(RomFileEntry *out_entry, RomFileId id) {
AMS_ASSERT(out_entry != nullptr);
Position pos = FileIdToPosition(id);
RomEntryKey key = {};
const Result file_res = m_file_table.GetByPosition(std::addressof(key), out_entry, pos);
R_UNLESS(R_FAILED(file_res), file_res);
R_UNLESS(fs::ResultDbmKeyNotFound::Includes(file_res), file_res);
RomDirectoryEntry entry = {};
const Result dir_res = m_dir_table.GetByPosition(std::addressof(key), std::addressof(entry), pos);
R_UNLESS(R_FAILED(dir_res), fs::ResultDbmInvalidOperation());
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), fs::ResultDbmFileNotFound());
R_RETURN(dir_res);
}
Result HierarchicalRomFileTable::OpenFile(FileInfo *out, const EntryKey &key) {
AMS_ASSERT(out != nullptr);
Position pos = 0;
RomFileEntry entry = {};
R_TRY(this->GetFileEntry(std::addressof(pos), std::addressof(entry), key));
*out = entry.info;
R_SUCCEED();
}
Result HierarchicalRomFileTable::FindOpen(FindPosition *out, const EntryKey &key) {
AMS_ASSERT(out != nullptr);
out->next_dir = InvalidPosition;
out->next_file = InvalidPosition;
Position pos = 0;
RomDirectoryEntry entry = {};
R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key));
out->next_dir = entry.dir;
out->next_file = entry.file;
R_SUCCEED();
}
}

View File

@@ -1,181 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
namespace ams::fs::RomPathTool {
Result PathParser::Initialize(const RomPathChar *path) {
AMS_ASSERT(path != nullptr);
/* Require paths start with a separator, and skip repeated separators. */
R_UNLESS(RomPathTool::IsSeparator(path[0]), fs::ResultDbmInvalidPathFormat());
while (RomPathTool::IsSeparator(path[1])) {
++path;
}
m_prev_path_start = path;
m_prev_path_end = path;
m_next_path = path + 1;
R_SUCCEED();
}
void PathParser::Finalize() {
m_prev_path_start = nullptr;
m_prev_path_end = nullptr;
m_next_path = nullptr;
m_finished = false;
}
bool PathParser::IsParseFinished() const {
return m_finished;
}
bool PathParser::IsDirectoryPath() const {
AMS_ASSERT(m_next_path != nullptr);
if (RomPathTool::IsNullTerminator(m_next_path[0]) && RomPathTool::IsSeparator(m_next_path[-1])) {
return true;
}
if (RomPathTool::IsCurrentDirectory(m_next_path)) {
return true;
}
return RomPathTool::IsParentDirectory(m_next_path);
}
Result PathParser::GetNextDirectoryName(RomEntryName *out) {
AMS_ASSERT(m_prev_path_start != nullptr);
AMS_ASSERT(m_prev_path_end != nullptr);
AMS_ASSERT(m_next_path != nullptr);
AMS_ASSERT(out != nullptr);
/* Get as directory name. */
R_TRY(this->GetAsDirectoryName(out));
/* Parse the next path. */
const RomPathChar *cur = m_next_path;
size_t name_len;
for (name_len = 0; !RomPathTool::IsSeparator(cur[name_len]); ++name_len) {
if (RomPathTool::IsNullTerminator(cur[name_len])) {
m_finished = true;
m_prev_path_start = m_next_path;
m_next_path = cur + name_len;
m_prev_path_end = cur + name_len;
R_SUCCEED();
}
}
/* Advance past separators. */
m_prev_path_start = m_next_path;
m_prev_path_end = cur + name_len;
for (m_next_path = m_prev_path_end + 1; RomPathTool::IsSeparator(m_next_path[0]); ++m_next_path) {
/* ... */
}
/* Check if we're finished. */
if (RomPathTool::IsNullTerminator(m_next_path[0])) {
m_finished = true;
}
R_SUCCEED();
}
Result PathParser::GetAsDirectoryName(RomEntryName *out) const {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(m_prev_path_start != nullptr);
AMS_ASSERT(m_prev_path_end != nullptr);
AMS_ASSERT(m_next_path != nullptr);
AMS_ASSERT(m_prev_path_start <= m_prev_path_end);
const size_t len = m_prev_path_end - m_prev_path_start;
R_UNLESS(len <= MaxPathLength, fs::ResultDbmDirectoryNameTooLong());
out->Initialize(m_prev_path_start, len);
R_SUCCEED();
}
Result PathParser::GetAsFileName(RomEntryName *out) const {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(m_prev_path_start != nullptr);
AMS_ASSERT(m_prev_path_end != nullptr);
AMS_ASSERT(m_next_path != nullptr);
AMS_ASSERT(m_prev_path_start <= m_prev_path_end);
const size_t len = m_prev_path_end - m_prev_path_start;
R_UNLESS(len <= MaxPathLength, fs::ResultDbmFileNameTooLong());
out->Initialize(m_prev_path_start, len);
R_SUCCEED();
}
Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p) {
AMS_ASSERT(out != nullptr);
AMS_ASSERT(p != nullptr);
const RomPathChar *start = cur.begin();
const RomPathChar *end = cur.end() - 1;
s32 depth = 1;
if (cur.IsParentDirectory()) {
++depth;
}
if (start > p) {
size_t len = 0;
for (const RomPathChar *head = start - 1; head >= p; --head) {
if (RomPathTool::IsSeparator(*head)) {
if (IsCurrentDirectory(head + 1, len)) {
++depth;
}
if (IsParentDirectory(head + 1, len)) {
depth += 2;
}
if (depth == 0) {
start = head + 1;
break;
}
do {
--head;
} while (head > p && RomPathTool::IsSeparator(*head));
end = head;
len = 0;
--depth;
}
++len;
}
R_UNLESS(depth == 0, fs::ResultDirectoryUnobtainable());
}
if (end <= p) {
out->Initialize(p, 0);
} else {
out->Initialize(start, end - start + 1);
}
R_SUCCEED();
}
}

View File

@@ -1,179 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
namespace ams::fs {
Result FileStorage::UpdateSize() {
R_SUCCEED_IF(m_size != InvalidSize);
R_RETURN(m_base_file->GetSize(std::addressof(m_size)));
}
Result FileStorage::Read(s64 offset, void *buffer, size_t size) {
/* Immediately succeed if there's nothing to read. */
R_SUCCEED_IF(size == 0);
/* Validate buffer. */
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
/* Ensure our size is valid. */
R_TRY(this->UpdateSize());
/* Ensure our access is valid. */
R_TRY(IStorage::CheckAccessRange(offset, size, m_size));
size_t read_size;
R_RETURN(m_base_file->Read(std::addressof(read_size), offset, buffer, size));
}
Result FileStorage::Write(s64 offset, const void *buffer, size_t size) {
/* Immediately succeed if there's nothing to write. */
R_SUCCEED_IF(size == 0);
/* Validate buffer. */
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
/* Ensure our size is valid. */
R_TRY(this->UpdateSize());
/* Ensure our access is valid. */
R_TRY(IStorage::CheckAccessRange(offset, size, m_size));
R_RETURN(m_base_file->Write(offset, buffer, size, fs::WriteOption()));
}
Result FileStorage::Flush() {
R_RETURN(m_base_file->Flush());
}
Result FileStorage::GetSize(s64 *out_size) {
R_TRY(this->UpdateSize());
*out_size = m_size;
R_SUCCEED();
}
Result FileStorage::SetSize(s64 size) {
m_size = InvalidSize;
R_RETURN(m_base_file->SetSize(size));
}
Result FileStorage::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
switch (op_id) {
case OperationId::Invalidate:
R_RETURN(m_base_file->OperateRange(OperationId::Invalidate, offset, size));
case OperationId::QueryRange:
if (size == 0) {
R_UNLESS(dst != nullptr, fs::ResultNullptrArgument());
R_UNLESS(dst_size == sizeof(QueryRangeInfo), fs::ResultInvalidSize());
reinterpret_cast<QueryRangeInfo *>(dst)->Clear();
R_SUCCEED();
}
R_TRY(this->UpdateSize());
R_TRY(IStorage::CheckOffsetAndSize(offset, size));
R_RETURN(m_base_file->OperateRange(dst, dst_size, op_id, offset, size, src, src_size));
default:
R_THROW(fs::ResultUnsupportedOperateRangeForFileStorage());
}
}
Result FileStorageBasedFileSystem::Initialize(std::shared_ptr<fs::fsa::IFileSystem> base_file_system, const fs::Path &path, fs::OpenMode mode) {
/* Open the file. */
std::unique_ptr<fs::fsa::IFile> base_file;
R_TRY(base_file_system->OpenFile(std::addressof(base_file), path, mode));
/* Set the file. */
this->SetFile(std::move(base_file));
m_base_file_system = std::move(base_file_system);
R_SUCCEED();
}
Result FileHandleStorage::UpdateSize() {
R_SUCCEED_IF(m_size != InvalidSize);
R_RETURN(GetFileSize(std::addressof(m_size), m_handle));
}
Result FileHandleStorage::Read(s64 offset, void *buffer, size_t size) {
/* Lock the mutex. */
std::scoped_lock lk(m_mutex);
/* Immediately succeed if there's nothing to read. */
R_SUCCEED_IF(size == 0);
/* Validate buffer. */
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
/* Ensure our size is valid. */
R_TRY(this->UpdateSize());
/* Ensure our access is valid. */
R_TRY(IStorage::CheckAccessRange(offset, size, m_size));
R_RETURN(ReadFile(m_handle, offset, buffer, size, fs::ReadOption()));
}
Result FileHandleStorage::Write(s64 offset, const void *buffer, size_t size) {
/* Lock the mutex. */
std::scoped_lock lk(m_mutex);
/* Immediately succeed if there's nothing to write. */
R_SUCCEED_IF(size == 0);
/* Validate buffer. */
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
/* Ensure our size is valid. */
R_TRY(this->UpdateSize());
/* Ensure our access is valid. */
R_TRY(IStorage::CheckAccessRange(offset, size, m_size));
R_RETURN(WriteFile(m_handle, offset, buffer, size, fs::WriteOption()));
}
Result FileHandleStorage::Flush() {
R_RETURN(FlushFile(m_handle));
}
Result FileHandleStorage::GetSize(s64 *out_size) {
R_TRY(this->UpdateSize());
*out_size = m_size;
R_SUCCEED();
}
Result FileHandleStorage::SetSize(s64 size) {
m_size = InvalidSize;
R_RETURN(SetFileSize(m_handle, size));
}
Result FileHandleStorage::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
AMS_UNUSED(src, src_size);
switch (op_id) {
case OperationId::QueryRange:
/* Validate buffer and size. */
R_UNLESS(dst != nullptr, fs::ResultNullptrArgument());
R_UNLESS(dst_size == sizeof(QueryRangeInfo), fs::ResultInvalidSize());
R_RETURN(QueryRange(static_cast<QueryRangeInfo *>(dst), m_handle, offset, size));
default:
R_THROW(fs::ResultUnsupportedOperateRangeForFileHandleStorage());
}
}
}

View File

@@ -1,910 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "impl/fs_file_system_proxy_service_object.hpp"
#include "fsa/fs_user_mount_table.hpp"
#include "fsa/fs_directory_accessor.hpp"
#include "fsa/fs_file_accessor.hpp"
#include "fsa/fs_filesystem_accessor.hpp"
#define AMS_FS_IMPL_ACCESS_LOG_AMS_API_VERSION "ams_version: " STRINGIZE(ATMOSPHERE_RELEASE_VERSION_MAJOR) "." STRINGIZE(ATMOSPHERE_RELEASE_VERSION_MINOR) "." STRINGIZE(ATMOSPHERE_RELEASE_VERSION_MICRO)
/* TODO: Other specs? */
#define AMS_FS_IMPL_ACCESS_LOG_SPEC "spec: NX"
namespace ams::fs {
/* Forward declare priority getter. */
fs::PriorityRaw GetPriorityRawOnCurrentThreadInternal();
namespace {
constinit u32 g_global_access_log_mode = fs::AccessLogMode_None;
constinit u32 g_local_access_log_target = fs::impl::AccessLogTarget_None;
constinit std::atomic_bool g_access_log_initialized = false;
constinit os::SdkMutex g_access_log_initialization_mutex;
void SetLocalAccessLogImpl(bool enabled) {
if (enabled) {
g_local_access_log_target |= fs::impl::AccessLogTarget_Application;
} else {
g_local_access_log_target &= ~fs::impl::AccessLogTarget_Application;
}
}
}
Result GetGlobalAccessLogMode(u32 *out) {
const auto fsp = impl::GetFileSystemProxyServiceObject();
AMS_FS_R_TRY(fsp->GetGlobalAccessLogMode(out));
R_SUCCEED();
}
Result SetGlobalAccessLogMode(u32 mode) {
const auto fsp = impl::GetFileSystemProxyServiceObject();
AMS_FS_R_TRY(fsp->SetGlobalAccessLogMode(mode));
R_SUCCEED();
}
void SetLocalAccessLog(bool enabled) {
SetLocalAccessLogImpl(enabled);
}
void SetLocalApplicationAccessLog(bool enabled) {
SetLocalAccessLogImpl(enabled);
}
void SetLocalSystemAccessLogForDebug(bool enabled) {
#if defined(AMS_BUILD_FOR_DEBUGGING)
if (enabled) {
g_local_access_log_target |= (fs::impl::AccessLogTarget_Application | fs::impl::AccessLogTarget_System);
} else {
g_local_access_log_target &= ~(fs::impl::AccessLogTarget_Application | fs::impl::AccessLogTarget_System);
}
#else
AMS_UNUSED(enabled);
#endif
}
}
namespace ams::fs::impl {
#define ADD_ENUM_CASE(v) case v: return #v
const char *IdString::ToValueString(int id) {
const int len = util::SNPrintf(m_buffer, sizeof(m_buffer), "%d", id);
AMS_ASSERT(static_cast<size_t>(len) < sizeof(m_buffer));
AMS_UNUSED(len);
return m_buffer;
}
template<> const char *IdString::ToString<fs::Priority>(fs::Priority id) {
switch (id) {
case fs::Priority_Realtime: return "Realtime";
case fs::Priority_Normal: return "Normal";
case fs::Priority_Low: return "Low";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fs::PriorityRaw>(fs::PriorityRaw id) {
switch (id) {
case fs::PriorityRaw_Realtime: return "Realtime";
case fs::PriorityRaw_Normal: return "Normal";
case fs::PriorityRaw_Low: return "Low";
case fs::PriorityRaw_Background: return "Realtime";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fs::ContentStorageId>(fs::ContentStorageId id) {
switch (id) {
using enum fs::ContentStorageId;
ADD_ENUM_CASE(User);
ADD_ENUM_CASE(System);
ADD_ENUM_CASE(SdCard);
ADD_ENUM_CASE(System0);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fs::SaveDataSpaceId>(fs::SaveDataSpaceId id) {
switch (id) {
using enum fs::SaveDataSpaceId;
ADD_ENUM_CASE(System);
ADD_ENUM_CASE(User);
ADD_ENUM_CASE(SdSystem);
ADD_ENUM_CASE(ProperSystem);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fs::ContentType>(fs::ContentType id) {
switch (id) {
case fs::ContentType_Meta: return "Meta";
case fs::ContentType_Control: return "Control";
case fs::ContentType_Manual: return "Manual";
case fs::ContentType_Logo: return "Logo";
case fs::ContentType_Data: return "Data";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fs::MountHostOption>(fs::MountHostOption id) {
if (id == MountHostOption::PseudoCaseSensitive) {
return "MountHostOptionFlag_PseudoCaseSensitive";
} else {
return ToValueString(static_cast<int>(id._value));
}
}
template<> const char *IdString::ToString<fs::BisPartitionId>(fs::BisPartitionId id) {
switch (id) {
using enum fs::BisPartitionId;
ADD_ENUM_CASE(BootPartition1Root);
ADD_ENUM_CASE(BootPartition2Root);
ADD_ENUM_CASE(UserDataRoot);
ADD_ENUM_CASE(BootConfigAndPackage2Part1);
ADD_ENUM_CASE(BootConfigAndPackage2Part2);
ADD_ENUM_CASE(BootConfigAndPackage2Part3);
ADD_ENUM_CASE(BootConfigAndPackage2Part4);
ADD_ENUM_CASE(BootConfigAndPackage2Part5);
ADD_ENUM_CASE(BootConfigAndPackage2Part6);
ADD_ENUM_CASE(CalibrationBinary);
ADD_ENUM_CASE(CalibrationFile);
ADD_ENUM_CASE(SafeMode);
ADD_ENUM_CASE(User);
ADD_ENUM_CASE(System);
ADD_ENUM_CASE(SystemProperEncryption);
ADD_ENUM_CASE(SystemProperPartition);
ADD_ENUM_CASE(DeviceTreeBlob);
ADD_ENUM_CASE(System0);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fs::DirectoryEntryType>(fs::DirectoryEntryType type) {
switch (type) {
case fs::DirectoryEntryType_Directory: return "Directory";
case fs::DirectoryEntryType_File: return "File";
default: return ToValueString(static_cast<int>(type));
}
}
template<> const char *IdString::ToString<fs::GameCardPartition>(fs::GameCardPartition id) {
switch (id) {
using enum fs::GameCardPartition;
ADD_ENUM_CASE(Update);
ADD_ENUM_CASE(Normal);
ADD_ENUM_CASE(Secure);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaHeader::ContentType>(fssystem::NcaHeader::ContentType id) {
switch (id) {
using enum fssystem::NcaHeader::ContentType;
ADD_ENUM_CASE(Program);
ADD_ENUM_CASE(Meta);
ADD_ENUM_CASE(Control);
ADD_ENUM_CASE(Manual);
ADD_ENUM_CASE(Data);
ADD_ENUM_CASE(PublicData);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaHeader::DistributionType>(fssystem::NcaHeader::DistributionType id) {
switch (id) {
using enum fssystem::NcaHeader::DistributionType;
ADD_ENUM_CASE(Download);
ADD_ENUM_CASE(GameCard);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaHeader::EncryptionType>(fssystem::NcaHeader::EncryptionType id) {
switch (id) {
using enum fssystem::NcaHeader::EncryptionType;
ADD_ENUM_CASE(Auto);
ADD_ENUM_CASE(None);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaHeader::DecryptionKey>(fssystem::NcaHeader::DecryptionKey id) {
switch (id) {
using enum fssystem::NcaHeader::DecryptionKey;
case DecryptionKey_AesXts1: return "AesXts1";
case DecryptionKey_AesXts2: return "AesXts2";
case DecryptionKey_AesCtr: return "AesCtr";
case DecryptionKey_AesCtrEx: return "AesCtrEx";
case DecryptionKey_AesCtrHw: return "AesCtrHw";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaFsHeader::FsType>(fssystem::NcaFsHeader::FsType id) {
switch (id) {
using enum fssystem::NcaFsHeader::FsType;
ADD_ENUM_CASE(RomFs);
ADD_ENUM_CASE(PartitionFs);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaFsHeader::EncryptionType>(fssystem::NcaFsHeader::EncryptionType id) {
switch (id) {
using enum fssystem::NcaFsHeader::EncryptionType;
ADD_ENUM_CASE(Auto);
ADD_ENUM_CASE(None);
ADD_ENUM_CASE(AesXts);
ADD_ENUM_CASE(AesCtr);
ADD_ENUM_CASE(AesCtrEx);
ADD_ENUM_CASE(AesCtrSkipLayerHash);
ADD_ENUM_CASE(AesCtrExSkipLayerHash);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaFsHeader::HashType>(fssystem::NcaFsHeader::HashType id) {
switch (id) {
using enum fssystem::NcaFsHeader::HashType;
ADD_ENUM_CASE(Auto);
ADD_ENUM_CASE(None);
ADD_ENUM_CASE(HierarchicalSha256Hash);
ADD_ENUM_CASE(HierarchicalIntegrityHash);
ADD_ENUM_CASE(AutoSha3);
ADD_ENUM_CASE(HierarchicalSha3256Hash);
ADD_ENUM_CASE(HierarchicalIntegritySha3Hash);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssystem::NcaFsHeader::MetaDataHashType>(fssystem::NcaFsHeader::MetaDataHashType id) {
switch (id) {
using enum fssystem::NcaFsHeader::MetaDataHashType;
ADD_ENUM_CASE(None);
ADD_ENUM_CASE(HierarchicalIntegrity);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<gc::impl::MemoryCapacity>(gc::impl::MemoryCapacity id) {
switch (id) {
using enum gc::impl::MemoryCapacity;
case MemoryCapacity_1GB: return "1GB";
case MemoryCapacity_2GB: return "2GB";
case MemoryCapacity_4GB: return "4GB";
case MemoryCapacity_8GB: return "8GB";
case MemoryCapacity_16GB: return "16GB";
case MemoryCapacity_32GB: return "32GB";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<gc::impl::SelSec>(gc::impl::SelSec id) {
switch (id) {
using enum gc::impl::SelSec;
case SelSec_T1: return "T1";
case SelSec_T2: return "T2";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<gc::impl::KekIndex>(gc::impl::KekIndex id) {
switch (id) {
using enum gc::impl::KekIndex;
case KekIndex_Version0: return "Version0";
case KekIndex_VersionForDev: return "VersionForDev";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<gc::impl::AccessControl1ClockRate>(gc::impl::AccessControl1ClockRate id) {
switch (id) {
using enum gc::impl::AccessControl1ClockRate;
case AccessControl1ClockRate_25MHz: return "25 MHz";
case AccessControl1ClockRate_50MHz: return "50 MHz";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<gc::impl::FwVersion>(gc::impl::FwVersion id) {
switch (id) {
using enum gc::impl::FwVersion;
case FwVersion_ForDev: return "ForDev";
case FwVersion_1_0_0: return "1.0.0";
case FwVersion_4_0_0: return "4.0.0";
case FwVersion_9_0_0: return "9.0.0";
case FwVersion_11_0_0: return "11.0.0";
case FwVersion_12_0_0: return "12.0.0";
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fs::GameCardCompatibilityType>(fs::GameCardCompatibilityType id) {
switch (id) {
using enum fs::GameCardCompatibilityType;
ADD_ENUM_CASE(Normal);
ADD_ENUM_CASE(Terra);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssrv::impl::AccessControlBits::Bits>(fssrv::impl::AccessControlBits::Bits id) {
switch (id) {
using enum fssrv::impl::AccessControlBits::Bits;
ADD_ENUM_CASE(ApplicationInfo);
ADD_ENUM_CASE(BootModeControl);
ADD_ENUM_CASE(Calibration);
ADD_ENUM_CASE(SystemSaveData);
ADD_ENUM_CASE(GameCard);
ADD_ENUM_CASE(SaveDataBackUp);
ADD_ENUM_CASE(SaveDataManagement);
ADD_ENUM_CASE(BisAllRaw);
ADD_ENUM_CASE(GameCardRaw);
ADD_ENUM_CASE(GameCardPrivate);
ADD_ENUM_CASE(SetTime);
ADD_ENUM_CASE(ContentManager);
ADD_ENUM_CASE(ImageManager);
ADD_ENUM_CASE(CreateSaveData);
ADD_ENUM_CASE(SystemSaveDataManagement);
ADD_ENUM_CASE(BisFileSystem);
ADD_ENUM_CASE(SystemUpdate);
ADD_ENUM_CASE(SaveDataMeta);
ADD_ENUM_CASE(DeviceSaveData);
ADD_ENUM_CASE(SettingsControl);
ADD_ENUM_CASE(SystemData);
ADD_ENUM_CASE(SdCard);
ADD_ENUM_CASE(Host);
ADD_ENUM_CASE(FillBis);
ADD_ENUM_CASE(CorruptSaveData);
ADD_ENUM_CASE(SaveDataForDebug);
ADD_ENUM_CASE(FormatSdCard);
ADD_ENUM_CASE(GetRightsId);
ADD_ENUM_CASE(RegisterExternalKey);
ADD_ENUM_CASE(RegisterUpdatePartition);
ADD_ENUM_CASE(SaveDataTransfer);
ADD_ENUM_CASE(DeviceDetection);
ADD_ENUM_CASE(AccessFailureResolution);
ADD_ENUM_CASE(SaveDataTransferVersion2);
ADD_ENUM_CASE(RegisterProgramIndexMapInfo);
ADD_ENUM_CASE(CreateOwnSaveData);
ADD_ENUM_CASE(MoveCacheStorage);
ADD_ENUM_CASE(Debug);
ADD_ENUM_CASE(FullPermission);
default: return ToValueString(util::CountTrailingZeros(util::ToUnderlying(id)));
}
}
template<> const char *IdString::ToString<fssrv::impl::AccessControl::AccessibilityType>(fssrv::impl::AccessControl::AccessibilityType id) {
switch (id) {
using enum fssrv::impl::AccessControl::AccessibilityType;
ADD_ENUM_CASE(MountLogo);
ADD_ENUM_CASE(MountContentMeta);
ADD_ENUM_CASE(MountContentControl);
ADD_ENUM_CASE(MountContentManual);
ADD_ENUM_CASE(MountContentData);
ADD_ENUM_CASE(MountApplicationPackage);
ADD_ENUM_CASE(MountSaveDataStorage);
ADD_ENUM_CASE(MountContentStorage);
ADD_ENUM_CASE(MountImageAndVideoStorage);
ADD_ENUM_CASE(MountCloudBackupWorkStorage);
ADD_ENUM_CASE(MountCustomStorage);
ADD_ENUM_CASE(MountBisCalibrationFile);
ADD_ENUM_CASE(MountBisSafeMode);
ADD_ENUM_CASE(MountBisUser);
ADD_ENUM_CASE(MountBisSystem);
ADD_ENUM_CASE(MountBisSystemProperEncryption);
ADD_ENUM_CASE(MountBisSystemProperPartition);
ADD_ENUM_CASE(MountSdCard);
ADD_ENUM_CASE(MountGameCard);
ADD_ENUM_CASE(MountDeviceSaveData);
ADD_ENUM_CASE(MountSystemSaveData);
ADD_ENUM_CASE(MountOthersSaveData);
ADD_ENUM_CASE(MountOthersSystemSaveData);
ADD_ENUM_CASE(OpenBisPartitionBootPartition1Root);
ADD_ENUM_CASE(OpenBisPartitionBootPartition2Root);
ADD_ENUM_CASE(OpenBisPartitionUserDataRoot);
ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part1);
ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part2);
ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part3);
ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part4);
ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part5);
ADD_ENUM_CASE(OpenBisPartitionBootConfigAndPackage2Part6);
ADD_ENUM_CASE(OpenBisPartitionCalibrationBinary);
ADD_ENUM_CASE(OpenBisPartitionCalibrationFile);
ADD_ENUM_CASE(OpenBisPartitionSafeMode);
ADD_ENUM_CASE(OpenBisPartitionUser);
ADD_ENUM_CASE(OpenBisPartitionSystem);
ADD_ENUM_CASE(OpenBisPartitionSystemProperEncryption);
ADD_ENUM_CASE(OpenBisPartitionSystemProperPartition);
ADD_ENUM_CASE(OpenSdCardStorage);
ADD_ENUM_CASE(OpenGameCardStorage);
ADD_ENUM_CASE(MountSystemDataPrivate);
ADD_ENUM_CASE(MountHost);
ADD_ENUM_CASE(MountRegisteredUpdatePartition);
ADD_ENUM_CASE(MountSaveDataInternalStorage);
ADD_ENUM_CASE(MountTemporaryDirectory);
ADD_ENUM_CASE(MountAllBaseFileSystem);
ADD_ENUM_CASE(NotMount);
default: return ToValueString(static_cast<int>(id));
}
}
template<> const char *IdString::ToString<fssrv::impl::AccessControl::OperationType>(fssrv::impl::AccessControl::OperationType id) {
switch (id) {
using enum fssrv::impl::AccessControl::OperationType;
ADD_ENUM_CASE(InvalidateBisCache);
ADD_ENUM_CASE(EraseMmc);
ADD_ENUM_CASE(GetGameCardDeviceCertificate);
ADD_ENUM_CASE(GetGameCardIdSet);
ADD_ENUM_CASE(FinalizeGameCardDriver);
ADD_ENUM_CASE(GetGameCardAsicInfo);
ADD_ENUM_CASE(CreateSaveData);
ADD_ENUM_CASE(DeleteSaveData);
ADD_ENUM_CASE(CreateSystemSaveData);
ADD_ENUM_CASE(CreateOthersSystemSaveData);
ADD_ENUM_CASE(DeleteSystemSaveData);
ADD_ENUM_CASE(OpenSaveDataInfoReader);
ADD_ENUM_CASE(OpenSaveDataInfoReaderForSystem);
ADD_ENUM_CASE(OpenSaveDataInfoReaderForInternal);
ADD_ENUM_CASE(OpenSaveDataMetaFile);
ADD_ENUM_CASE(SetCurrentPosixTime);
ADD_ENUM_CASE(ReadSaveDataFileSystemExtraData);
ADD_ENUM_CASE(SetGlobalAccessLogMode);
ADD_ENUM_CASE(SetSpeedEmulationMode);
ADD_ENUM_CASE(Debug);
ADD_ENUM_CASE(FillBis);
ADD_ENUM_CASE(CorruptSaveData);
ADD_ENUM_CASE(CorruptSystemSaveData);
ADD_ENUM_CASE(VerifySaveData);
ADD_ENUM_CASE(DebugSaveData);
ADD_ENUM_CASE(FormatSdCard);
ADD_ENUM_CASE(GetRightsId);
ADD_ENUM_CASE(RegisterExternalKey);
ADD_ENUM_CASE(SetEncryptionSeed);
ADD_ENUM_CASE(WriteSaveDataFileSystemExtraDataTimeStamp);
ADD_ENUM_CASE(WriteSaveDataFileSystemExtraDataFlags);
ADD_ENUM_CASE(WriteSaveDataFileSystemExtraDataCommitId);
ADD_ENUM_CASE(WriteSaveDataFileSystemExtraDataAll);
ADD_ENUM_CASE(ExtendSaveData);
ADD_ENUM_CASE(ExtendSystemSaveData);
ADD_ENUM_CASE(ExtendOthersSystemSaveData);
ADD_ENUM_CASE(RegisterUpdatePartition);
ADD_ENUM_CASE(OpenSaveDataTransferManager);
ADD_ENUM_CASE(OpenSaveDataTransferManagerVersion2);
ADD_ENUM_CASE(OpenSaveDataTransferManagerForSaveDataRepair);
ADD_ENUM_CASE(OpenSaveDataTransferManagerForSaveDataRepairTool);
ADD_ENUM_CASE(OpenSaveDataTransferProhibiter);
ADD_ENUM_CASE(OpenSaveDataMover);
ADD_ENUM_CASE(OpenBisWiper);
ADD_ENUM_CASE(ListAccessibleSaveDataOwnerId);
ADD_ENUM_CASE(ControlMmcPatrol);
ADD_ENUM_CASE(OverrideSaveDataTransferTokenSignVerificationKey);
ADD_ENUM_CASE(OpenSdCardDetectionEventNotifier);
ADD_ENUM_CASE(OpenGameCardDetectionEventNotifier);
ADD_ENUM_CASE(OpenSystemDataUpdateEventNotifier);
ADD_ENUM_CASE(NotifySystemDataUpdateEvent);
ADD_ENUM_CASE(OpenAccessFailureDetectionEventNotifier);
ADD_ENUM_CASE(GetAccessFailureDetectionEvent);
ADD_ENUM_CASE(IsAccessFailureDetected);
ADD_ENUM_CASE(ResolveAccessFailure);
ADD_ENUM_CASE(AbandonAccessFailure);
ADD_ENUM_CASE(QuerySaveDataInternalStorageTotalSize);
ADD_ENUM_CASE(GetSaveDataCommitId);
ADD_ENUM_CASE(SetSdCardAccessibility);
ADD_ENUM_CASE(SimulateDevice);
ADD_ENUM_CASE(CreateSaveDataWithHashSalt);
ADD_ENUM_CASE(RegisterProgramIndexMapInfo);
ADD_ENUM_CASE(ChallengeCardExistence);
ADD_ENUM_CASE(CreateOwnSaveData);
ADD_ENUM_CASE(DeleteOwnSaveData);
ADD_ENUM_CASE(ReadOwnSaveDataFileSystemExtraData);
ADD_ENUM_CASE(ExtendOwnSaveData);
ADD_ENUM_CASE(OpenOwnSaveDataTransferProhibiter);
ADD_ENUM_CASE(FindOwnSaveDataWithFilter);
ADD_ENUM_CASE(OpenSaveDataTransferManagerForRepair);
ADD_ENUM_CASE(SetDebugConfiguration);
ADD_ENUM_CASE(OpenDataStorageByPath);
default: return ToValueString(static_cast<int>(id));
}
}
namespace {
class AccessLogPrinterCallbackManager {
private:
AccessLogPrinterCallback m_callback;
public:
constexpr AccessLogPrinterCallbackManager() : m_callback(nullptr) { /* ... */ }
constexpr bool IsRegisteredCallback() const { return m_callback != nullptr; }
constexpr void RegisterCallback(AccessLogPrinterCallback c) {
AMS_ASSERT(m_callback == nullptr);
m_callback = c;
}
constexpr int InvokeCallback(char *buf, size_t size) const {
AMS_ASSERT(m_callback != nullptr);
return m_callback(buf, size);
}
};
constinit AccessLogPrinterCallbackManager g_access_log_manager_printer_callback_manager;
ALWAYS_INLINE AccessLogPrinterCallbackManager &GetStartAccessLogPrinterCallbackManager() {
return g_access_log_manager_printer_callback_manager;
}
const char *GetPriorityRawName(fs::impl::IdString &id_string) {
return id_string.ToString(fs::GetPriorityRawOnCurrentThreadInternal());
}
Result OutputAccessLogToSdCardImpl(const char *log, size_t size) {
const auto fsp = impl::GetFileSystemProxyServiceObject();
AMS_FS_R_TRY(fsp->OutputAccessLogToSdCard(sf::InBuffer(log, size)));
R_SUCCEED();
}
void OutputAccessLogToSdCard(const char *format, std::va_list vl) {
if ((g_global_access_log_mode & AccessLogMode_SdCard) != 0) {
/* Create a buffer to hold the log's input string. */
int log_buffer_size = 1_KB;
auto log_buffer = fs::impl::MakeUnique<char[]>(log_buffer_size);
while (true) {
if (log_buffer == nullptr) {
return;
}
const auto size = util::VSNPrintf(log_buffer.get(), log_buffer_size, format, vl);
if (size < log_buffer_size) {
break;
}
log_buffer_size = size + 1;
log_buffer = fs::impl::MakeUnique<char[]>(log_buffer_size);
}
/* Output. */
OutputAccessLogToSdCardImpl(log_buffer.get(), log_buffer_size - 1);
}
}
void OutputAccessLogImpl(const char *log, size_t size) {
if ((g_global_access_log_mode & AccessLogMode_Log) != 0) {
/* TODO: Support logging. */
} else if ((g_global_access_log_mode & AccessLogMode_SdCard) != 0) {
OutputAccessLogToSdCardImpl(log, size - 1);
}
}
void OutputAccessLog(Result result, const char *priority, os::Tick start, os::Tick end, const char *name, const void *handle, const char *format, std::va_list vl) {
/* Create a buffer to hold the log's input string. */
int str_buffer_size = 1_KB;
auto str_buffer = fs::impl::MakeUnique<char[]>(str_buffer_size);
while (true) {
if (str_buffer == nullptr) {
return;
}
const auto size = util::VSNPrintf(str_buffer.get(), str_buffer_size, format, vl);
if (size < str_buffer_size) {
break;
}
str_buffer_size = size + 1;
str_buffer = fs::impl::MakeUnique<char[]>(str_buffer_size);
}
/* Create a buffer to hold the log. */
int log_buffer_size = 0;
decltype(str_buffer) log_buffer;
{
/* Declare format string. */
constexpr const char FormatString[] = "FS_ACCESS { "
"start: %9" PRId64 ", "
"end: %9" PRId64 ", "
"result: 0x%08" PRIX32 ", "
"handle: 0x%p, "
"priority: %s, "
"function: \"%s\""
"%s"
" }\n";
/* Convert the timing to ms. */
const s64 start_ms = start.ToTimeSpan().GetMilliSeconds();
const s64 end_ms = end.ToTimeSpan().GetMilliSeconds();
/* Print the log. */
int try_size = std::max<int>(str_buffer_size + sizeof(FormatString) + 0x100, 1_KB);
while (true) {
log_buffer = fs::impl::MakeUnique<char[]>(try_size);
if (log_buffer == nullptr) {
return;
}
log_buffer_size = 1 + util::SNPrintf(log_buffer.get(), try_size, FormatString, start_ms, end_ms, result.GetValue(), handle, priority, name, str_buffer.get());
if (log_buffer_size <= try_size) {
break;
}
try_size = log_buffer_size;
}
}
OutputAccessLogImpl(log_buffer.get(), log_buffer_size);
}
void GetProgramIndexForAccessLog(u32 *out_index, u32 *out_count) {
if (hos::GetVersion() >= hos::Version_7_0_0) {
/* Use libnx bindings if available. */
const auto fsp = impl::GetFileSystemProxyServiceObject();
R_ABORT_UNLESS(fsp->GetProgramIndexForAccessLog(out_index, out_count));
} else {
/* Use hardcoded defaults. */
*out_index = 0;
*out_count = 0;
}
}
void OutputAccessLogStart() {
/* Get the program index. */
u32 program_index = 0, program_count = 0;
GetProgramIndexForAccessLog(std::addressof(program_index), std::addressof(program_count));
/* Print the log buffer. */
if (program_count < 2) {
constexpr const char StartLog[] = "FS_ACCESS: { "
AMS_FS_IMPL_ACCESS_LOG_AMS_API_VERSION ", "
AMS_FS_IMPL_ACCESS_LOG_SPEC
" }\n";
OutputAccessLogImpl(StartLog, sizeof(StartLog));
} else {
constexpr const char StartLog[] = "FS_ACCESS: { "
AMS_FS_IMPL_ACCESS_LOG_AMS_API_VERSION ", "
AMS_FS_IMPL_ACCESS_LOG_SPEC ", "
"program_index: %d"
" }\n";
char log_buffer[0x80];
const int len = 1 + util::SNPrintf(log_buffer, sizeof(log_buffer), StartLog, static_cast<int>(program_index));
if (static_cast<size_t>(len) <= sizeof(log_buffer)) {
OutputAccessLogImpl(log_buffer, len);
}
}
}
[[maybe_unused]] void OutputAccessLogStartForSystem() {
constexpr const char StartLog[] = "FS_ACCESS: { "
AMS_FS_IMPL_ACCESS_LOG_AMS_API_VERSION ", "
AMS_FS_IMPL_ACCESS_LOG_SPEC ", "
"for_system: true"
" }\n";
OutputAccessLogImpl(StartLog, sizeof(StartLog));
}
void OutputAccessLogStartGeneratedByCallback() {
/* Get the manager. */
const auto &manager = GetStartAccessLogPrinterCallbackManager();
if (manager.IsRegisteredCallback()) {
/* Invoke the callback. */
char log_buffer[0x80];
const int len = 1 + manager.InvokeCallback(log_buffer, sizeof(log_buffer));
/* Print, if we fit. */
if (static_cast<size_t>(len) <= sizeof(log_buffer)) {
OutputAccessLogImpl(log_buffer, len);
}
}
}
}
bool IsEnabledAccessLog(u32 target) {
/* If we don't need to log to the target, return false. */
if ((g_local_access_log_target & target) == 0) {
return false;
}
/* Ensure we've initialized. */
if (!g_access_log_initialized) {
std::scoped_lock lk(g_access_log_initialization_mutex);
if (!g_access_log_initialized) {
#if defined (AMS_BUILD_FOR_DEBUGGING)
if ((g_local_access_log_target & fs::impl::AccessLogTarget_System) != 0)
{
g_global_access_log_mode = AccessLogMode_Log;
OutputAccessLogStartForSystem();
OutputAccessLogStartGeneratedByCallback();
}
else
#endif
{
AMS_FS_R_ABORT_UNLESS(GetGlobalAccessLogMode(std::addressof(g_global_access_log_mode)));
if (g_global_access_log_mode != AccessLogMode_None) {
OutputAccessLogStart();
OutputAccessLogStartGeneratedByCallback();
}
}
g_access_log_initialized = true;
}
}
return g_global_access_log_mode != AccessLogMode_None;
}
bool IsEnabledAccessLog() {
return IsEnabledAccessLog(fs::impl::AccessLogTarget_Application | fs::impl::AccessLogTarget_System);
}
void RegisterStartAccessLogPrinterCallback(AccessLogPrinterCallback callback) {
GetStartAccessLogPrinterCallbackManager().RegisterCallback(callback);
}
void OutputAccessLog(Result result, fs::Priority priority, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) {
std::va_list vl;
va_start(vl, fmt);
OutputAccessLog(result, fs::impl::IdString().ToString(priority), start, end, name, handle, fmt, vl);
va_end(vl);
}
void OutputAccessLog(Result result, fs::PriorityRaw priority_raw, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...){
std::va_list vl;
va_start(vl, fmt);
OutputAccessLog(result, fs::impl::IdString().ToString(priority_raw), start, end, name, handle, fmt, vl);
va_end(vl);
}
void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::FileHandle handle, const char *fmt, ...) {
std::va_list vl;
va_start(vl, fmt);
fs::impl::IdString id_string;
OutputAccessLog(result, GetPriorityRawName(id_string), start, end, name, handle.handle, fmt, vl);
va_end(vl);
}
void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::DirectoryHandle handle, const char *fmt, ...) {
std::va_list vl;
va_start(vl, fmt);
fs::impl::IdString id_string;
OutputAccessLog(result, GetPriorityRawName(id_string), start, end, name, handle.handle, fmt, vl);
va_end(vl);
}
void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, fs::impl::IdentifyAccessLogHandle handle, const char *fmt, ...) {
std::va_list vl;
va_start(vl, fmt);
fs::impl::IdString id_string;
OutputAccessLog(result, GetPriorityRawName(id_string), start, end, name, handle.handle, fmt, vl);
va_end(vl);
}
void OutputAccessLog(Result result, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) {
std::va_list vl;
va_start(vl, fmt);
fs::impl::IdString id_string;
OutputAccessLog(result, GetPriorityRawName(id_string), start, end, name, handle, fmt, vl);
va_end(vl);
}
void OutputAccessLogToOnlySdCard(const char *fmt, ...) {
std::va_list vl;
va_start(vl, fmt);
OutputAccessLogToSdCard(fmt, vl);
va_end(vl);
}
void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, fs::FileHandle handle, const char *fmt, ...) {
if (R_FAILED(result)) {
std::va_list vl;
va_start(vl, fmt);
fs::impl::IdString id_string;
OutputAccessLog(result, GetPriorityRawName(id_string), start, end, name, handle.handle, fmt, vl);
va_end(vl);
}
}
void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, fs::DirectoryHandle handle, const char *fmt, ...) {
if (R_FAILED(result)) {
std::va_list vl;
va_start(vl, fmt);
fs::impl::IdString id_string;
OutputAccessLog(result, GetPriorityRawName(id_string), start, end, name, handle.handle, fmt, vl);
va_end(vl);
}
}
void OutputAccessLogUnlessResultSuccess(Result result, os::Tick start, os::Tick end, const char *name, const void *handle, const char *fmt, ...) {
if (R_FAILED(result)) {
std::va_list vl;
va_start(vl, fmt);
fs::impl::IdString id_string;
OutputAccessLog(result, GetPriorityRawName(id_string), start, end, name, handle, fmt, vl);
va_end(vl);
}
}
bool IsEnabledHandleAccessLog(fs::FileHandle handle) {
/* Get the file accessor. */
impl::FileAccessor *accessor = reinterpret_cast<impl::FileAccessor *>(handle.handle);
if (accessor == nullptr) {
return true;
}
/* Check the parent. */
if (auto *parent = accessor->GetParent(); parent != nullptr) {
return parent->IsEnabledAccessLog();
} else {
return false;
}
}
bool IsEnabledHandleAccessLog(fs::DirectoryHandle handle) {
/* Get the file accessor. */
impl::DirectoryAccessor *accessor = reinterpret_cast<impl::DirectoryAccessor *>(handle.handle);
if (accessor == nullptr) {
return true;
}
/* Check the parent. */
if (auto *parent = accessor->GetParent(); parent != nullptr) {
return parent->IsEnabledAccessLog();
} else {
return false;
}
}
bool IsEnabledHandleAccessLog(fs::impl::IdentifyAccessLogHandle handle) {
AMS_UNUSED(handle);
return true;
}
bool IsEnabledHandleAccessLog(const void *handle) {
if (handle == nullptr) {
return true;
}
/* We should never receive non-null here. */
AMS_ASSERT(handle == nullptr);
return false;
}
bool IsEnabledFileSystemAccessorAccessLog(const char *mount_name) {
/* Get the accessor. */
impl::FileSystemAccessor *accessor = nullptr;
if (R_FAILED(impl::Find(std::addressof(accessor), mount_name))) {
return true;
}
return accessor->IsEnabledAccessLog();
}
void EnableFileSystemAccessorAccessLog(const char *mount_name) {
/* Get the accessor. */
impl::FileSystemAccessor *accessor = nullptr;
AMS_FS_R_ABORT_UNLESS(impl::Find(std::addressof(accessor), mount_name));
accessor->SetAccessLogEnabled(true);
}
}

View File

@@ -1,195 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fs_remote_file_system_proxy.hpp"
#include "fs_remote_file_system_proxy_for_loader.hpp"
#include "impl/fs_library.hpp"
namespace ams::fs {
#if defined(ATMOSPHERE_OS_HORIZON)
namespace {
alignas(0x10) constinit std::byte g_fsp_service_object_buffer[0x80] = {};
alignas(0x10) constinit std::byte g_fsp_ldr_service_object_buffer[0x80] = {};
constinit bool g_use_static_fsp_service_object_buffer = false;
constinit bool g_use_static_fsp_ldr_service_object_buffer = false;
class HipcClientAllocator {
public:
using Policy = sf::StatelessAllocationPolicy<HipcClientAllocator>;
public:
constexpr HipcClientAllocator() = default;
void *Allocate(size_t size) {
if (g_use_static_fsp_service_object_buffer) {
return std::addressof(g_fsp_service_object_buffer);
} else if (g_use_static_fsp_ldr_service_object_buffer) {
return std::addressof(g_fsp_ldr_service_object_buffer);
} else {
return ::ams::fs::impl::Allocate(size);
}
}
void Deallocate(void *ptr, size_t size) {
if (ptr == std::addressof(g_fsp_service_object_buffer)) {
return;
} else if (ptr == std::addressof(g_fsp_ldr_service_object_buffer)) {
return;
} else {
return ::ams::fs::impl::Deallocate(ptr, size);
}
}
};
enum class FileSystemProxySessionSetting {
SystemNormal = 0,
Application = 1,
SystemMulti = 2,
};
constexpr ALWAYS_INLINE int GetSessionCount(FileSystemProxySessionSetting setting) {
switch (setting) {
case FileSystemProxySessionSetting::Application: return 3;
case FileSystemProxySessionSetting::SystemNormal: return 1;
case FileSystemProxySessionSetting::SystemMulti: return 2;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
constinit bool g_is_fsp_object_initialized = false;
constinit FileSystemProxySessionSetting g_fsp_session_setting = FileSystemProxySessionSetting::SystemNormal;
/* TODO: SessionResourceManager */
}
#endif
namespace {
constinit sf::SharedPointer<fssrv::sf::IFileSystemProxy> g_fsp_service_object;
sf::SharedPointer<fssrv::sf::IFileSystemProxy> GetFileSystemProxyServiceObjectImpl() {
/* Ensure the library is initialized. */
::ams::fs::impl::InitializeFileSystemLibrary();
sf::SharedPointer<fssrv::sf::IFileSystemProxy> fsp_object;
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_OS_HORIZON)
/* Try to use the custom object. */
fsp_object = g_fsp_service_object;
/* If we don't have one, create a remote object. */
if (fsp_object == nullptr) {
/* Make our next allocation use our static reserved buffer for the service object. */
g_use_static_fsp_service_object_buffer = true;
ON_SCOPE_EXIT { g_use_static_fsp_service_object_buffer = false; };
using ObjectFactory = sf::ObjectFactory<HipcClientAllocator::Policy>;
/* Create the object. */
fsp_object = ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystemProxy, RemoteFileSystemProxy>(GetSessionCount(g_fsp_session_setting));
AMS_ABORT_UNLESS(fsp_object != nullptr);
/* Set the current process. */
fsp_object->SetCurrentProcess({});
}
#else
/* On non-horizon, use the system object. */
fsp_object = fssrv::impl::GetFileSystemProxyServiceObject();
AMS_ABORT_UNLESS(fsp_object != nullptr);
/* Set the current process. */
fsp_object->SetCurrentProcess({});
#endif
/* Return the object. */
return fsp_object;
}
sf::SharedPointer<fssrv::sf::IFileSystemProxyForLoader> GetFileSystemProxyForLoaderServiceObjectImpl() {
/* Ensure the library is initialized. */
::ams::fs::impl::InitializeFileSystemLibrary();
sf::SharedPointer<fssrv::sf::IFileSystemProxyForLoader> fsp_ldr_object;
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_OS_HORIZON)
/* Make our next allocation use our static reserved buffer for the service object. */
g_use_static_fsp_ldr_service_object_buffer = true;
ON_SCOPE_EXIT { g_use_static_fsp_ldr_service_object_buffer = false; };
using ObjectFactory = sf::ObjectFactory<HipcClientAllocator::Policy>;
/* Create the object. */
fsp_ldr_object = ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystemProxyForLoader, RemoteFileSystemProxyForLoader>();
AMS_ABORT_UNLESS(fsp_ldr_object != nullptr);
#else
/* On non-horizon, use the system object. */
fsp_ldr_object = fssrv::impl::GetFileSystemProxyForLoaderServiceObject();
AMS_ABORT_UNLESS(fsp_ldr_object != nullptr);
#endif
/* Return the object. */
return fsp_ldr_object;
}
}
namespace impl {
sf::SharedPointer<fssrv::sf::IFileSystemProxy> GetFileSystemProxyServiceObject() {
AMS_FUNCTION_LOCAL_STATIC(sf::SharedPointer<fssrv::sf::IFileSystemProxy>, s_fsp_service_object, GetFileSystemProxyServiceObjectImpl());
return s_fsp_service_object;
}
sf::SharedPointer<fssrv::sf::IFileSystemProxyForLoader> GetFileSystemProxyForLoaderServiceObject() {
AMS_FUNCTION_LOCAL_STATIC(sf::SharedPointer<fssrv::sf::IFileSystemProxyForLoader>, s_fsp_ldr_service_object, GetFileSystemProxyForLoaderServiceObjectImpl());
return s_fsp_ldr_service_object;
}
}
void InitializeForHostTool() {
#if !defined(ATMOSPHERE_OS_HORIZON)
AMS_ABORT_UNLESS(impl::GetFileSystemProxyServiceObject() != nullptr);
R_ABORT_UNLESS(::ams::fs::MountHostRoot());
#endif
}
void InitializeForSystem() {
#if defined(ATMOSPHERE_OS_HORIZON)
AMS_ABORT_UNLESS(!g_is_fsp_object_initialized);
AMS_ABORT_UNLESS(g_fsp_session_setting == FileSystemProxySessionSetting::SystemNormal);
g_fsp_session_setting = FileSystemProxySessionSetting::SystemNormal;
/* Nintendo doesn't do this, but we have to for timing reasons. */
AMS_ABORT_UNLESS(impl::GetFileSystemProxyServiceObject() != nullptr);
#endif
}
void InitializeWithMultiSessionForSystem() {
#if defined(ATMOSPHERE_OS_HORIZON)
AMS_ABORT_UNLESS(!g_is_fsp_object_initialized);
AMS_ABORT_UNLESS(g_fsp_session_setting == FileSystemProxySessionSetting::SystemNormal);
g_fsp_session_setting = FileSystemProxySessionSetting::SystemMulti;
/* Nintendo doesn't do this, but we have to for timing reasons. */
AMS_ABORT_UNLESS(impl::GetFileSystemProxyServiceObject() != nullptr);
#endif
}
}

View File

@@ -1,57 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_service_object_adapter.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
namespace ams::fs {
Result MountApplicationPackage(const char *name, const char *common_path) {
auto mount_impl = [=]() -> Result {
/* Validate the mount name. */
R_TRY(impl::CheckMountName(name));
/* Validate the path. */
R_UNLESS(common_path != nullptr, fs::ResultInvalidPath());
/* Convert the path for ipc. */
fssrv::sf::FspPath sf_path;
R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), common_path));
/* Open the filesystem. */
auto fsp = impl::GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
R_TRY(fsp->OpenFileSystemWithId(std::addressof(fs), sf_path, fs::ContentAttributes_None, ncm::InvalidProgramId.value, impl::FileSystemProxyType_Package));
/* Allocate a new filesystem wrapper. */
auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs));
R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInApplicationA());
/* Register. */
R_RETURN(fsa::Register(name, std::move(fsa)));
};
/* Perform the mount. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_APPLICATION_PACKAGE(name, common_path)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
}

View File

@@ -1,136 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_service_object_adapter.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
namespace ams::fs {
namespace {
class BisCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable {
private:
const BisPartitionId m_id;
public:
explicit BisCommonMountNameGenerator(BisPartitionId i) : m_id(i) { /* ... */ }
virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override {
/* Determine how much space we need. */
const char *bis_mount_name = GetBisMountName(m_id);
const size_t needed_size = util::Strnlen(bis_mount_name, MountNameLengthMax) + 2;
AMS_ABORT_UNLESS(dst_size >= needed_size);
/* Generate the name. */
const auto size = util::SNPrintf(dst, dst_size, "%s:", bis_mount_name);
AMS_ASSERT(static_cast<size_t>(size) == needed_size - 1);
AMS_UNUSED(size);
R_SUCCEED();
}
};
}
namespace impl {
Result MountBisImpl(const char *name, BisPartitionId id, const char *root_path) {
auto mount_impl = [=]() -> Result {
/* Validate the mount name. */
R_TRY(impl::CheckMountNameAllowingReserved(name));
/* Convert the path for ipc. */
/* NOTE: Nintendo ignores the root_path here. */
fssrv::sf::FspPath sf_path;
sf_path.str[0] = '\x00';
AMS_UNUSED(root_path);
/* Open the filesystem. */
auto fsp = impl::GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
R_TRY(fsp->OpenBisFileSystem(std::addressof(fs), sf_path, static_cast<u32>(id)));
/* Allocate a new mountname generator. */
auto generator = std::make_unique<BisCommonMountNameGenerator>(id);
R_UNLESS(generator != nullptr, fs::ResultAllocationMemoryFailedInBisA());
/* Allocate a new filesystem wrapper. */
auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs));
R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInBisB());
/* Register. */
R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator)));
};
/* Perform the mount. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_BIS(name, id, root_path)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
Result SetBisRootForHostImpl(BisPartitionId id, const char *root_path) {
AMS_UNUSED(id, root_path);
AMS_ABORT("TODO");
}
}
const char *GetBisMountName(BisPartitionId id) {
switch (id) {
case BisPartitionId::CalibrationFile: return impl::BisCalibrationFilePartitionMountName;
case BisPartitionId::SafeMode: return impl::BisSafeModePartitionMountName;
case BisPartitionId::User: return impl::BisUserPartitionMountName;
case BisPartitionId::System: return impl::BisSystemPartitionMountName;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
Result MountBis(BisPartitionId id, const char *root_path) {
R_RETURN(impl::MountBisImpl(GetBisMountName(id), id, root_path));
}
Result MountBis(const char *name, BisPartitionId id) {
R_RETURN(impl::MountBisImpl(name, id, nullptr));
}
void SetBisRootForHost(BisPartitionId id, const char *root_path) {
R_ABORT_UNLESS(impl::SetBisRootForHostImpl(id, root_path));
}
Result OpenBisPartition(std::unique_ptr<fs::IStorage> *out, BisPartitionId id) {
/* Open the partition. */
auto fsp = impl::GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IStorage> s;
AMS_FS_R_TRY(fsp->OpenBisStorage(std::addressof(s), static_cast<u32>(id)));
/* Allocate a new storage wrapper. */
auto storage = std::make_unique<impl::StorageServiceObjectAdapter<fssrv::sf::IStorage>>(std::move(s));
AMS_FS_R_UNLESS(storage != nullptr, fs::ResultAllocationMemoryFailedInBisC());
*out = std::move(storage);
R_SUCCEED();
}
Result InvalidateBisCache() {
auto fsp = impl::GetFileSystemProxyServiceObject();
AMS_FS_R_ABORT_UNLESS(fsp->InvalidateBisCache());
R_SUCCEED();
}
}

View File

@@ -1,486 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_service_object_adapter.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
namespace ams::fs {
namespace {
constinit os::SdkMutex g_mount_stratosphere_romfs_lock;
constinit bool g_mounted_stratosphere_romfs = false;
constinit util::TypedStorage<FileHandleStorage> g_stratosphere_romfs_storage = {};
constinit util::TypedStorage<RomFsFileSystem> g_stratosphere_romfs_fs = {};
Result EnsureStratosphereRomfsMounted() {
std::scoped_lock lk(g_mount_stratosphere_romfs_lock);
if (AMS_UNLIKELY(!g_mounted_stratosphere_romfs)) {
/* Mount the SD card. */
R_TRY(fs::MountSdCard("#strat-romfs-sd"));
auto sd_guard = SCOPE_GUARD { fs::Unmount("#strat-romfs-sd"); };
/* Open sd:/atmosphere/stratosphere.romfs. */
fs::FileHandle stratosphere_romfs_file;
R_TRY(fs::OpenFile(std::addressof(stratosphere_romfs_file), "#strat-romfs-sd:/atmosphere/stratosphere.romfs", fs::OpenMode_Read));
/* Setup the storage. */
/* NOTE: This owns the file, and so on failure it will be closed appropriately. */
auto storage_guard = util::ConstructAtGuarded(g_stratosphere_romfs_storage, stratosphere_romfs_file, true);
/* Create the filesystem. */
auto fs_guard = util::ConstructAtGuarded(g_stratosphere_romfs_fs);
/* Initialize the filesystem. */
R_TRY(GetReference(g_stratosphere_romfs_fs).Initialize(GetPointer(g_stratosphere_romfs_storage), nullptr, 0, false));
/* We succeeded, and so stratosphere.romfs is mounted. */
fs_guard.Cancel();
storage_guard.Cancel();
sd_guard.Cancel();
g_mounted_stratosphere_romfs = true;
}
R_SUCCEED();
}
fsa::IFileSystem &GetStratosphereRomFsFileSystem() {
/* Ensure that stratosphere.romfs is mounted. */
/* NOTE: Abort is used here to ensure that atmosphere's filesystem is structurally valid. */
R_ABORT_UNLESS(EnsureStratosphereRomfsMounted());
return GetReference(g_stratosphere_romfs_fs);
}
Result OpenCodeFileSystemImpl(CodeVerificationData *out_verification_data, std::unique_ptr<fsa::IFileSystem> *out, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id) {
/* Print a path suitable for the remote service. */
fssrv::sf::Path sf_path;
R_TRY(FormatToFspPath(std::addressof(sf_path), "%s", path));
/* Open the filesystem. */
auto fsp = impl::GetFileSystemProxyForLoaderServiceObject();
R_TRY(fsp->SetCurrentProcess({}));
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
if (hos::GetVersion() >= hos::Version_20_0_0) {
R_TRY(fsp->OpenCodeFileSystem(std::addressof(fs), ams::sf::OutBuffer(out_verification_data, sizeof(*out_verification_data)), attr, program_id, storage_id));
} else {
R_TRY(fsp->OpenCodeFileSystemDeprecated4(std::addressof(fs), ams::sf::OutBuffer(out_verification_data, sizeof(*out_verification_data)), sf_path, attr, program_id));
}
/* Allocate a new filesystem wrapper. */
auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs));
R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInCodeA());
*out = std::move(fsa);
R_SUCCEED();
}
Result OpenPackageFileSystemImpl(std::unique_ptr<fsa::IFileSystem> *out, const fssrv::sf::FspPath &path) {
/* Open the filesystem. */
auto fsp = impl::GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
R_TRY(fsp->OpenFileSystemWithId(std::addressof(fs), path, fs::ContentAttributes_None, ncm::InvalidProgramId.value, impl::FileSystemProxyType_Package));
/* Allocate a new filesystem wrapper. */
auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs));
R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInCodeA());
*out = std::move(fsa);
R_SUCCEED();
}
Result OpenSdCardCodeFileSystemImpl(std::unique_ptr<fsa::IFileSystem> *out, ncm::ProgramId program_id) {
/* Ensure we don't access the SD card too early. */
R_UNLESS(cfg::IsSdCardInitialized(), fs::ResultSdCardNotPresent());
/* Print a path to the program's package. */
fssrv::sf::Path sf_path;
R_TRY(FormatToFspPath(std::addressof(sf_path), "%s:/atmosphere/contents/%016" PRIx64 "/exefs.nsp", impl::SdCardFileSystemMountName, program_id.value));
R_RETURN(OpenPackageFileSystemImpl(out, sf_path));
}
Result OpenStratosphereCodeFileSystemImpl(std::unique_ptr<fsa::IFileSystem> *out, ncm::ProgramId program_id) {
/* Ensure we don't access the SD card too early. */
R_UNLESS(cfg::IsSdCardInitialized(), fs::ResultSdCardNotPresent());
/* Open the program's package. */
std::unique_ptr<fsa::IFile> package_file;
{
/* Get the stratosphere.romfs filesystem. */
auto &romfs_fs = GetStratosphereRomFsFileSystem();
/* Print a path to the program's package. */
fs::Path path;
R_TRY(path.InitializeWithFormat("/atmosphere/contents/%016" PRIx64 "/exefs.nsp", program_id.value));
R_TRY(path.Normalize(fs::PathFlags{}));
/* Open the package within stratosphere.romfs. */
R_TRY(romfs_fs.OpenFile(std::addressof(package_file), path, fs::OpenMode_Read));
}
/* Create a file storage for the program's package. */
auto package_storage = fs::AllocateShared<FileStorage>(std::move(package_file));
R_UNLESS(package_storage != nullptr, fs::ResultAllocationMemoryFailedInCodeA());
/* Create a partition filesystem. */
auto package_fs = std::make_unique<fssystem::PartitionFileSystem>();
R_UNLESS(package_fs != nullptr, fs::ResultAllocationMemoryFailedInCodeA());
/* Initialize the partition filesystem. */
R_TRY(package_fs->Initialize(package_storage));
*out = std::move(package_fs);
R_SUCCEED();
}
Result OpenSdCardCodeOrStratosphereCodeOrCodeFileSystemImpl(CodeVerificationData *out_verification_data, std::unique_ptr<fsa::IFileSystem> *out, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id) {
/* If we can open an sd card code fs, use it. */
R_SUCCEED_IF(R_SUCCEEDED(OpenSdCardCodeFileSystemImpl(out, program_id)));
/* If we can open a stratosphere code fs, use it. */
R_SUCCEED_IF(R_SUCCEEDED(OpenStratosphereCodeFileSystemImpl(out, program_id)));
/* Otherwise, fall back to a normal code fs. */
R_RETURN(OpenCodeFileSystemImpl(out_verification_data, out, path, attr, program_id, storage_id));
}
Result OpenHblCodeFileSystemImpl(std::unique_ptr<fsa::IFileSystem> *out) {
/* Get the HBL path. */
const char *hbl_path = cfg::GetHblPath();
/* Print a path to the hbl package. */
fssrv::sf::Path sf_path;
R_TRY(FormatToFspPath(std::addressof(sf_path), "%s:/%s", impl::SdCardFileSystemMountName, hbl_path[0] == '/' ? hbl_path + 1 : hbl_path));
R_RETURN(OpenPackageFileSystemImpl(out, sf_path));
}
Result OpenSdCardFileSystemImpl(std::shared_ptr<fsa::IFileSystem> *out) {
/* Open the SD card filesystem. */
auto fsp = impl::GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
R_TRY(fsp->OpenSdCardFileSystem(std::addressof(fs)));
/* Allocate a new filesystem wrapper. */
auto fsa = fs::AllocateShared<impl::FileSystemServiceObjectAdapter>(std::move(fs));
R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInCodeA());
*out = std::move(fsa);
R_SUCCEED();
}
class OpenFileOnlyFileSystem : public fsa::IFileSystem, public impl::Newable {
private:
virtual Result DoCommit() override final {
R_SUCCEED();
}
virtual Result DoOpenDirectory(std::unique_ptr<fsa::IDirectory> *out_dir, const fs::Path &path, OpenDirectoryMode mode) override final {
AMS_UNUSED(out_dir, path, mode);
R_THROW(fs::ResultUnsupportedOperation());
}
virtual Result DoGetEntryType(DirectoryEntryType *out, const fs::Path &path) override final {
AMS_UNUSED(out, path);
R_THROW(fs::ResultUnsupportedOperation());
}
virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override final {
AMS_UNUSED(path, size, flags);
R_THROW(fs::ResultUnsupportedOperation());
}
virtual Result DoDeleteFile(const fs::Path &path) override final {
AMS_UNUSED(path);
R_THROW(fs::ResultUnsupportedOperation());
}
virtual Result DoCreateDirectory(const fs::Path &path) override final {
AMS_UNUSED(path);
R_THROW(fs::ResultUnsupportedOperation());
}
virtual Result DoDeleteDirectory(const fs::Path &path) override final {
AMS_UNUSED(path);
R_THROW(fs::ResultUnsupportedOperation());
}
virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override final {
AMS_UNUSED(path);
R_THROW(fs::ResultUnsupportedOperation());
}
virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override final {
AMS_UNUSED(old_path, new_path);
R_THROW(fs::ResultUnsupportedOperation());
}
virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override final {
AMS_UNUSED(old_path, new_path);
R_THROW(fs::ResultUnsupportedOperation());
}
virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override final {
AMS_UNUSED(path);
R_THROW(fs::ResultUnsupportedOperation());
}
virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override final {
AMS_UNUSED(out, path);
R_THROW(fs::ResultUnsupportedOperation());
}
virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override final {
AMS_UNUSED(out, path);
R_THROW(fs::ResultUnsupportedOperation());
}
virtual Result DoCommitProvisionally(s64 counter) override final {
AMS_UNUSED(counter);
R_THROW(fs::ResultUnsupportedOperation());
}
};
class SdCardRedirectionCodeFileSystem : public OpenFileOnlyFileSystem {
private:
util::optional<ReadOnlyFileSystem> m_sd_content_fs;
ReadOnlyFileSystem m_code_fs;
bool m_is_redirect;
public:
SdCardRedirectionCodeFileSystem(std::unique_ptr<fsa::IFileSystem> &&code, ncm::ProgramId program_id, bool redirect) : m_code_fs(std::move(code)), m_is_redirect(redirect) {
if (!cfg::IsSdCardInitialized()) {
return;
}
/* Open an SD card filesystem. */
std::shared_ptr<fsa::IFileSystem> sd_fs;
if (R_FAILED(OpenSdCardFileSystemImpl(std::addressof(sd_fs)))) {
return;
}
/* Create a redirection filesystem to the relevant content folder. */
auto subdir_fs = std::make_unique<fssystem::SubDirectoryFileSystem>(std::move(sd_fs));
if (subdir_fs == nullptr) {
return;
}
fs::Path path;
R_ABORT_UNLESS(path.InitializeWithFormat("/atmosphere/contents/%016" PRIx64 "/exefs", program_id.value));
R_ABORT_UNLESS(path.Normalize(fs::PathFlags{}));
R_ABORT_UNLESS(subdir_fs->Initialize(path));
m_sd_content_fs.emplace(std::move(subdir_fs));
}
private:
bool IsFileStubbed(const fs::Path &path) {
/* If we don't have an sd content fs, nothing is stubbed. */
if (!m_sd_content_fs) {
return false;
}
/* Create a path representing the stub. */
fs::Path stub_path;
if (R_FAILED(stub_path.InitializeWithFormat("%s.stub", path.GetString()))) {
return false;
}
if (R_FAILED(stub_path.Normalize(fs::PathFlags{}))) {
return false;
}
/* Query whether we have the file. */
bool has_file;
if (R_FAILED(fssystem::HasFile(std::addressof(has_file), std::addressof(*m_sd_content_fs), stub_path))) {
return false;
}
return has_file;
}
virtual Result DoOpenFile(std::unique_ptr<fsa::IFile> *out_file, const fs::Path &path, OpenMode mode) override final {
/* Only allow opening files with mode = read. */
R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidOpenMode());
/* If we support redirection, we'd like to prefer a file from the sd card. */
if (m_is_redirect) {
R_SUCCEED_IF(R_SUCCEEDED(m_sd_content_fs->OpenFile(out_file, path, mode)));
}
/* Otherwise, check if the file is stubbed. */
R_UNLESS(!this->IsFileStubbed(path), fs::ResultPathNotFound());
/* Open a file from the base code fs. */
R_RETURN(m_code_fs.OpenFile(out_file, path, mode));
}
};
class AtmosphereCodeFileSystem : public OpenFileOnlyFileSystem {
private:
util::optional<SdCardRedirectionCodeFileSystem> m_code_fs;
util::optional<ReadOnlyFileSystem> m_hbl_fs;
ncm::ProgramId m_program_id;
ncm::StorageId m_storage_id;
bool m_initialized;
public:
AtmosphereCodeFileSystem() : m_initialized(false) { /* ... */ }
Result Initialize(CodeVerificationData *out_verification_data, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id, bool is_hbl, bool is_specific) {
AMS_ABORT_UNLESS(!m_initialized);
/* If we're hbl, we need to open a hbl fs. */
if (is_hbl) {
std::unique_ptr<fsa::IFileSystem> fsa;
R_TRY(OpenHblCodeFileSystemImpl(std::addressof(fsa)));
m_hbl_fs.emplace(std::move(fsa));
}
/* Open the code filesystem. */
std::unique_ptr<fsa::IFileSystem> fsa;
R_TRY(OpenSdCardCodeOrStratosphereCodeOrCodeFileSystemImpl(out_verification_data, std::addressof(fsa), path, attr, program_id, storage_id));
m_code_fs.emplace(std::move(fsa), program_id, is_specific);
m_program_id = program_id;
m_storage_id = storage_id;
m_initialized = true;
R_SUCCEED();
}
private:
virtual Result DoOpenFile(std::unique_ptr<fsa::IFile> *out_file, const fs::Path &path, OpenMode mode) override final {
/* Ensure that we're initialized. */
R_UNLESS(m_initialized, fs::ResultNotInitialized());
/* Only allow opening files with mode = read. */
R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidOpenMode());
/* First, check if there's an external code. */
{
fsa::IFileSystem *ecs = fssystem::GetExternalCodeFileSystem(m_program_id);
if (ecs != nullptr) {
R_RETURN(ecs->OpenFile(out_file, path, mode));
}
}
/* If we're hbl, open from the hbl fs. */
if (m_hbl_fs) {
R_RETURN(m_hbl_fs->OpenFile(out_file, path, mode));
}
/* If we're not hbl, fall back to our code filesystem. */
R_RETURN(m_code_fs->OpenFile(out_file, path, mode));
}
};
}
Result MountCode(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id) {
auto mount_impl = [=]() -> Result {
/* Clear the output. */
std::memset(out, 0, sizeof(*out));
/* Validate the mount name. */
R_TRY(impl::CheckMountName(name));
/* Validate the path isn't null. */
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
/* Open the code file system. */
std::unique_ptr<fsa::IFileSystem> fsa;
R_TRY(OpenCodeFileSystemImpl(out, std::addressof(fsa), path, attr, program_id, storage_id));
/* Register. */
R_RETURN(fsa::Register(name, std::move(fsa)));
};
/* Perform the mount. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CODE(name, path, program_id)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
Result MountCodeForAtmosphereWithRedirection(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id, bool is_hbl, bool is_specific) {
auto mount_impl = [=]() -> Result {
/* Clear the output. */
std::memset(out, 0, sizeof(*out));
/* Validate the mount name. */
R_TRY(impl::CheckMountName(name));
/* Validate the path isn't null. */
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
/* Create an AtmosphereCodeFileSystem. */
auto ams_code_fs = std::make_unique<AtmosphereCodeFileSystem>();
R_UNLESS(ams_code_fs != nullptr, fs::ResultAllocationMemoryFailedInCodeA());
/* Initialize the code file system. */
R_TRY(ams_code_fs->Initialize(out, path, attr, program_id, storage_id, is_hbl, is_specific));
/* Register. */
R_RETURN(fsa::Register(name, std::move(ams_code_fs)));
};
/* Perform the mount. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CODE(name, path, program_id)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
Result MountCodeForAtmosphere(CodeVerificationData *out, const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id) {
auto mount_impl = [=]() -> Result {
/* Clear the output. */
std::memset(out, 0, sizeof(*out));
/* Validate the mount name. */
R_TRY(impl::CheckMountName(name));
/* Validate the path isn't null. */
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
/* Open the code file system. */
std::unique_ptr<fsa::IFileSystem> fsa;
R_TRY(OpenSdCardCodeOrStratosphereCodeOrCodeFileSystemImpl(out, std::addressof(fsa), path, attr, program_id, storage_id));
/* Create a wrapper fs. */
auto wrap_fsa = std::make_unique<SdCardRedirectionCodeFileSystem>(std::move(fsa), program_id, false);
R_UNLESS(wrap_fsa != nullptr, fs::ResultAllocationMemoryFailedInCodeA());
/* Register. */
R_RETURN(fsa::Register(name, std::move(wrap_fsa)));
};
/* Perform the mount. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CODE(name, path, program_id)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
}

View File

@@ -1,106 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
#include "impl/fs_file_system_service_object_adapter.hpp"
namespace ams::fs {
namespace {
impl::FileSystemProxyType ConvertToFileSystemProxyType(ContentType content_type) {
switch (content_type) {
case ContentType_Control: return impl::FileSystemProxyType_Control;
case ContentType_Manual: return impl::FileSystemProxyType_Manual;
case ContentType_Meta: return impl::FileSystemProxyType_Meta;
case ContentType_Data: return impl::FileSystemProxyType_Data;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
Result MountContentImpl(const char *name, const char *path, fs::ContentAttributes attr, u64 id, ContentType type) {
/* Validate the mount name. */
R_TRY(impl::CheckMountNameAllowingReserved(name));
/* Validate the path. */
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
/* Convert the path for fsp. */
fssrv::sf::FspPath sf_path;
R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path));
/* Open the filesystem. */
auto fsp = impl::GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
R_TRY(fsp->OpenFileSystemWithId(std::addressof(fs), sf_path, attr, id, ConvertToFileSystemProxyType(type)));
/* Allocate a new filesystem wrapper. */
auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs));
R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInContentA());
/* Register. */
R_RETURN(fsa::Register(name, std::move(fsa)));
}
}
Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ContentType content_type) {
auto mount_impl = [=]() -> Result {
/* This API only supports mounting Meta content. */
R_UNLESS(content_type == ContentType_Meta, fs::ResultInvalidArgument());
R_RETURN(MountContentImpl(name, path, attr, ncm::InvalidProgramId.value, content_type));
};
/* Perform the mount. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH(name, path, content_type)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ncm::ProgramId id, ContentType content_type) {
auto mount_impl = [=]() -> Result {
R_RETURN(MountContentImpl(name, path, attr, id.value, content_type));
};
/* Perform the mount. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH_AND_PROGRAM_ID(name, path, id, content_type)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
Result MountContent(const char *name, const char *path, fs::ContentAttributes attr, ncm::DataId id, ContentType content_type) {
auto mount_impl = [=]() -> Result {
R_RETURN(MountContentImpl(name, path, attr, id.value, content_type));
};
/* Perform the mount. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH_AND_DATA_ID(name, path, id, content_type)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
}

View File

@@ -1,112 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_service_object_adapter.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
namespace ams::fs {
namespace {
class ContentStorageCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable {
private:
const ContentStorageId id;
public:
explicit ContentStorageCommonMountNameGenerator(ContentStorageId i) : id(i) { /* ... */ }
virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override {
/* Determine how much space we need. */
const size_t needed_size = util::Strnlen(GetContentStorageMountName(id), MountNameLengthMax) + 2;
AMS_ABORT_UNLESS(dst_size >= needed_size);
/* Generate the name. */
const auto size = util::SNPrintf(dst, dst_size, "%s:", GetContentStorageMountName(id));
AMS_ASSERT(static_cast<size_t>(size) == needed_size - 1);
AMS_UNUSED(size);
R_SUCCEED();
}
};
}
const char *GetContentStorageMountName(ContentStorageId id) {
switch (id) {
case ContentStorageId::System: return impl::ContentStorageSystemMountName;
case ContentStorageId::User: return impl::ContentStorageUserMountName;
case ContentStorageId::SdCard: return impl::ContentStorageSdCardMountName;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
Result MountContentStorage(ContentStorageId id) {
R_RETURN(MountContentStorage(GetContentStorageMountName(id), id));
}
Result MountContentStorage(const char *name, ContentStorageId id) {
auto mount_impl = [=]() -> Result {
/* Validate the mount name. */
R_TRY(impl::CheckMountNameAllowingReserved(name));
/* It can take some time for the system partition to be ready (if it's on the SD card). */
/* Thus, we will retry up to 10 times, waiting one second each time. */
constexpr size_t MaxRetries = 10;
constexpr auto RetryInterval = TimeSpan::FromSeconds(1);
/* Mount the content storage */
auto fsp = impl::GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
for (size_t i = 0; i < MaxRetries; i++) {
/* Try to open the filesystem. */
R_TRY_CATCH(fsp->OpenContentStorageFileSystem(std::addressof(fs), static_cast<u32>(id))) {
R_CATCH(fs::ResultSystemPartitionNotReady) {
if (i < MaxRetries - 1) {
os::SleepThread(RetryInterval);
continue;
} else {
R_THROW(fs::ResultSystemPartitionNotReady());
}
}
} R_END_TRY_CATCH;
/* The filesystem was opened successfully. */
break;
}
/* Allocate a new filesystem wrapper. */
auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs));
R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInContentStorageA());
/* Allocate a new mountname generator. */
auto generator = std::make_unique<ContentStorageCommonMountNameGenerator>(id);
R_UNLESS(generator != nullptr, fs::ResultAllocationMemoryFailedInContentStorageB());
/* Register. */
R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator)));
};
/* Perform the mount. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_STORAGE(name, id)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
}

View File

@@ -1,76 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
namespace ams::fs {
namespace {
constinit bool g_auto_abort_enabled = true;
/* NOTE: This generates a global constructor. */
os::SdkThreadLocalStorage g_context_tls;
}
void SetEnabledAutoAbort(bool enabled) {
g_auto_abort_enabled = enabled;
}
AbortSpecifier DefaultResultHandler(Result result) {
AMS_UNUSED(result);
if (g_auto_abort_enabled) {
return AbortSpecifier::Default;
} else {
return AbortSpecifier::Return;
}
}
AbortSpecifier AlwaysReturnResultHandler(Result result) {
AMS_UNUSED(result);
return AbortSpecifier::Return;
}
constinit FsContext g_default_context(DefaultResultHandler);
constinit FsContext g_always_return_context(AlwaysReturnResultHandler);
void SetDefaultFsContextResultHandler(const ResultHandler handler) {
if (handler == nullptr) {
g_default_context.SetHandler(DefaultResultHandler);
} else {
g_default_context.SetHandler(handler);
}
}
const FsContext *GetCurrentThreadFsContext() {
const FsContext *context = reinterpret_cast<const FsContext *>(g_context_tls.GetValue());
if (context == nullptr) {
context = std::addressof(g_default_context);
}
return context;
}
void SetCurrentThreadFsContext(const FsContext *context) {
g_context_tls.SetValue(reinterpret_cast<uintptr_t>(context));
}
ScopedAutoAbortDisabler::ScopedAutoAbortDisabler() : m_prev_context(GetCurrentThreadFsContext()) {
SetCurrentThreadFsContext(std::addressof(g_always_return_context));
}
}

View File

@@ -1,96 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
namespace ams::fs::impl {
namespace {
Result OpenDataStorageByDataIdImpl(sf::SharedPointer<fssrv::sf::IStorage> *out, ncm::DataId data_id, ncm::StorageId storage_id) {
auto fsp = impl::GetFileSystemProxyServiceObject();
R_TRY_CATCH(fsp->OpenDataStorageByDataId(out, data_id, static_cast<u8>(storage_id))) {
R_CONVERT(ncm::ResultContentMetaNotFound, fs::ResultTargetNotFound());
} R_END_TRY_CATCH;
R_SUCCEED();
}
Result OpenDataStorageByDataId(std::unique_ptr<ams::fs::IStorage> *out, ncm::DataId data_id, ncm::StorageId storage_id) {
/* Open storage. */
sf::SharedPointer<fssrv::sf::IStorage> s;
AMS_FS_R_TRY(OpenDataStorageByDataIdImpl(std::addressof(s), data_id, storage_id));
auto storage = std::make_unique<impl::StorageServiceObjectAdapter<fssrv::sf::IStorage>>(std::move(s));
R_UNLESS(storage != nullptr, fs::ResultAllocationMemoryFailedInDataA());
*out = std::move(storage);
R_SUCCEED();
}
Result MountDataImpl(const char *name, ncm::DataId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size, bool use_cache, bool use_data_cache, bool use_path_cache) {
std::unique_ptr<fs::IStorage> storage;
R_TRY(OpenDataStorageByDataId(std::addressof(storage), data_id, storage_id));
auto fs = std::make_unique<RomFsFileSystem>();
R_UNLESS(fs != nullptr, fs::ResultAllocationMemoryFailedInDataB());
R_TRY(fs->Initialize(std::move(storage), cache_buffer, cache_size, use_cache));
R_RETURN(fsa::Register(name, std::move(fs), nullptr, use_data_cache, use_path_cache, false));
}
}
Result QueryMountDataCacheSize(size_t *out, ncm::DataId data_id, ncm::StorageId storage_id) {
AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
std::unique_ptr<fs::IStorage> storage;
AMS_FS_R_TRY(OpenDataStorageByDataId(std::addressof(storage), data_id, storage_id));
size_t size = 0;
AMS_FS_R_TRY(RomFsFileSystem::GetRequiredWorkingMemorySize(std::addressof(size), storage.get()));
constexpr size_t MinimumCacheSize = 32;
*out = std::max(size, MinimumCacheSize);
R_SUCCEED();
}
Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id) {
/* Validate the mount name. */
AMS_FS_R_TRY(impl::CheckMountName(name));
R_RETURN(MountDataImpl(name, data_id, storage_id, nullptr, 0, false, false, false));
}
Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size) {
/* Validate the mount name. */
AMS_FS_R_TRY(impl::CheckMountName(name));
AMS_FS_R_UNLESS(cache_buffer != nullptr, fs::ResultNullptrArgument());
R_RETURN(MountDataImpl(name, data_id, storage_id, cache_buffer, cache_size, true, false, false));
}
Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size, bool use_data_cache, bool use_path_cache) {
/* Validate the mount name. */
AMS_FS_R_TRY(impl::CheckMountName(name));
AMS_FS_R_UNLESS(cache_buffer != nullptr, fs::ResultNullptrArgument());
R_RETURN(MountDataImpl(name, data_id, storage_id, cache_buffer, cache_size, true, use_data_cache, use_path_cache));
}
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
#include "impl/fs_file_system_service_object_adapter.hpp"
namespace ams::fs {
namespace {
constexpr inline SaveDataSpaceId DeviceSaveDataSpaceId = SaveDataSpaceId::User;
Result MountDeviceSaveDataImpl(const char *name, const SaveDataAttribute &attribute) {
/* Validate the mount name. */
R_TRY(impl::CheckMountName(name));
/* Open the filesystem. */
auto fsp = impl::GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
R_TRY(fsp->OpenSaveDataFileSystem(std::addressof(fs), static_cast<u8>(DeviceSaveDataSpaceId), attribute));
/* Allocate a new filesystem wrapper. */
auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs));
R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInDeviceSaveDataA());
/* Register. */
R_RETURN(fsa::Register(name, std::move(fsa)));
}
}
Result MountDeviceSaveData(const char *name) {
const auto attr = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::Device, InvalidUserId, InvalidSystemSaveDataId);
/* Perform the mount. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(MountDeviceSaveDataImpl(name, attr), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, name));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
Result MountDeviceSaveData(const char *name, const ncm::ApplicationId application_id) {
const auto attr = SaveDataAttribute::Make(application_id, SaveDataType::Device, InvalidUserId, InvalidSystemSaveDataId);
/* Perform the mount. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(MountDeviceSaveDataImpl(name, attr), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_DEVICE_SAVE_DATA_APPLICATION_ID(name, application_id)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
}

View File

@@ -1,35 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
#include "impl/fs_file_system_service_object_adapter.hpp"
namespace ams::fs {
Result GetAndClearFileSystemProxyErrorInfo(FileSystemProxyErrorInfo *out) {
/* Check pre-conditions. */
AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Get the error info. */
AMS_FS_R_TRY(fsp->GetAndClearErrorInfo(out));
R_SUCCEED();
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 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::fs::impl {
constexpr inline size_t FilePathHashSize = 4;
struct FilePathHash : public Newable {
u8 data[FilePathHashSize];
};
static_assert(util::is_pod<FilePathHash>::value);
inline bool operator==(const FilePathHash &lhs, const FilePathHash &rhs) {
return std::memcmp(lhs.data, rhs.data, FilePathHashSize) == 0;
}
inline bool operator!=(const FilePathHash &lhs, const FilePathHash &rhs) {
return !(lhs == rhs);
}
}

View File

@@ -1,79 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "fsa/fs_filesystem_accessor.hpp"
namespace ams::fs {
Result EnsureDirectory(const char *path) {
/* Get the filesystem accessor and sub path. */
impl::FileSystemAccessor *accessor;
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
/* Set up the true sub path. */
fs::Path sub_fs_path;
R_TRY(accessor->SetUpPath(std::addressof(sub_fs_path), sub_path));
/* Use the system implementation. */
R_RETURN(fssystem::EnsureDirectory(accessor->GetRawFileSystemUnsafe(), sub_fs_path));
}
Result EnsureParentDirectory(const char *path) {
/* Get the filesystem accessor and sub path. */
impl::FileSystemAccessor *accessor;
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
/* Set up the true sub path. */
fs::Path sub_fs_path;
R_TRY(accessor->SetUpPath(std::addressof(sub_fs_path), sub_path));
/* Convert the path to the parent directory path. */
R_TRY(sub_fs_path.RemoveChild());
/* Use the system implementation. */
R_RETURN(fssystem::EnsureDirectory(accessor->GetRawFileSystemUnsafe(), sub_fs_path));
}
Result HasFile(bool *out, const char *path) {
/* Get the filesystem accessor and sub path. */
impl::FileSystemAccessor *accessor;
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
/* Set up the true sub path. */
fs::Path sub_fs_path;
R_TRY(accessor->SetUpPath(std::addressof(sub_fs_path), sub_path));
R_RETURN(fssystem::HasFile(out, accessor->GetRawFileSystemUnsafe(), sub_fs_path));
}
Result HasDirectory(bool *out, const char *path) {
/* Get the filesystem accessor and sub path. */
impl::FileSystemAccessor *accessor;
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
/* Set up the true sub path. */
fs::Path sub_fs_path;
R_TRY(accessor->SetUpPath(std::addressof(sub_fs_path), sub_path));
R_RETURN(fssystem::HasDirectory(out, accessor->GetRawFileSystemUnsafe(), sub_fs_path));
}
}

View File

@@ -1,164 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
#include "impl/fs_file_system_service_object_adapter.hpp"
namespace ams::fs {
namespace {
const char *GetGameCardMountNameSuffix(GameCardPartition which) {
switch (which) {
case GameCardPartition::Update: return impl::GameCardFileSystemMountNameUpdateSuffix;
case GameCardPartition::Normal: return impl::GameCardFileSystemMountNameNormalSuffix;
case GameCardPartition::Secure: return impl::GameCardFileSystemMountNameSecureSuffix;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
class GameCardCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable {
private:
const GameCardHandle m_handle;
const GameCardPartition m_partition;
public:
explicit GameCardCommonMountNameGenerator(GameCardHandle h, GameCardPartition p) : m_handle(h), m_partition(p) { /* ... */ }
virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override {
/* Determine how much space we need. */
const size_t needed_size = util::Strnlen(impl::GameCardFileSystemMountName, MountNameLengthMax) + util::Strnlen(GetGameCardMountNameSuffix(m_partition), MountNameLengthMax) + sizeof(GameCardHandle) * 2 + 2;
AMS_ABORT_UNLESS(dst_size >= needed_size);
/* Generate the name. */
const auto size = util::SNPrintf(dst, dst_size, "%s%s%08x:", impl::GameCardFileSystemMountName, GetGameCardMountNameSuffix(m_partition), m_handle);
AMS_ASSERT(static_cast<size_t>(size) == needed_size - 1);
AMS_UNUSED(size);
R_SUCCEED();
}
};
}
Result GetGameCardHandle(GameCardHandle *out) {
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get the handle. */
u32 handle;
AMS_FS_R_TRY(device_operator->GetGameCardHandle(std::addressof(handle)));
*out = handle;
R_SUCCEED();
}
Result MountGameCardPartition(const char *name, GameCardHandle handle, GameCardPartition partition) {
auto mount_impl = [=]() -> Result {
/* Validate the mount name. */
R_TRY(impl::CheckMountNameAllowingReserved(name));
/* Open the gamecard filesystem. */
auto fsp = impl::GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
R_TRY(fsp->OpenGameCardFileSystem(std::addressof(fs), static_cast<u32>(handle), static_cast<u32>(partition)));
/* Allocate a new filesystem wrapper. */
auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs));
R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInGameCardC());
/* Allocate a new mountname generator. */
auto generator = std::make_unique<GameCardCommonMountNameGenerator>(handle, partition);
R_UNLESS(generator != nullptr, fs::ResultAllocationMemoryFailedInGameCardD());
/* Register. */
R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator)));
};
/* Perform the mount. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_GAME_CARD_PARTITION(name, handle, partition)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
bool IsGameCardInserted() {
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_ABORT_UNLESS(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get insertion status. */
bool inserted;
AMS_FS_R_ABORT_UNLESS(device_operator->IsGameCardInserted(std::addressof(inserted)));
return inserted;
}
Result GetGameCardCid(void *dst, size_t size) {
/* Check pre-conditions. */
AMS_FS_R_UNLESS(size >= sizeof(gc::GameCardIdSet), fs::ResultInvalidSize());
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get the id set. */
gc::GameCardIdSet gc_id_set;
AMS_FS_R_TRY(device_operator->GetGameCardIdSet(sf::OutBuffer(std::addressof(gc_id_set), sizeof(gc_id_set)), static_cast<s64>(sizeof(gc_id_set))));
/* Copy the id set to output. */
std::memcpy(dst, std::addressof(gc_id_set), sizeof(gc_id_set));
R_SUCCEED();
}
Result GetGameCardDeviceId(void *dst, size_t size) {
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get the cid. */
AMS_FS_R_TRY(device_operator->GetGameCardDeviceId(sf::OutBuffer(dst, size), static_cast<s64>(size)));
R_SUCCEED();
}
Result GetGameCardErrorReportInfo(GameCardErrorReportInfo *out) {
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get the error report info. */
AMS_FS_R_TRY(device_operator->GetGameCardErrorReportInfo(out));
R_SUCCEED();
}
}

View File

@@ -1,241 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
#include "impl/fs_file_system_service_object_adapter.hpp"
namespace ams::fs {
namespace {
class HostRootCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable {
public:
explicit HostRootCommonMountNameGenerator() { /* ... */ }
virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override {
/* Determine how much space we need. */
constexpr size_t RequiredNameBufferSizeSize = AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + 1 + 1;
AMS_ASSERT(dst_size >= RequiredNameBufferSizeSize);
AMS_UNUSED(RequiredNameBufferSizeSize);
/* Generate the name. */
const auto size = util::SNPrintf(dst, dst_size, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME ":");
AMS_ASSERT(static_cast<size_t>(size) == RequiredNameBufferSizeSize - 1);
AMS_UNUSED(size);
R_SUCCEED();
}
};
class HostCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable {
private:
char m_path[fs::EntryNameLengthMax + 1];
public:
HostCommonMountNameGenerator(const char *path) {
util::Strlcpy<char>(m_path, path, sizeof(m_path));
}
virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override {
/* Determine how much space we need. */
const size_t required_size = AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + 1 + util::Strnlen<char>(m_path, sizeof(m_path)) + 1; /* @Host:%s */
R_UNLESS(dst_size >= required_size, fs::ResultTooLongPath());
/* Generate the name. */
const auto size = util::SNPrintf(dst, dst_size, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME ":%s", m_path);
AMS_ASSERT(static_cast<size_t>(size) == required_size - 1);
AMS_UNUSED(size);
R_SUCCEED();
}
};
Result OpenHostFileSystemImpl(std::unique_ptr<fs::fsa::IFileSystem> *out, const fssrv::sf::FspPath &path, const MountHostOption &option) {
/* Open the filesystem. */
auto fsp = impl::GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
if (option != MountHostOption::None) {
R_TRY(fsp->OpenHostFileSystemWithOption(std::addressof(fs), path, option._value));
} else {
R_TRY(fsp->OpenHostFileSystem(std::addressof(fs), path));
}
/* Allocate a new filesystem wrapper. */
auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs));
R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInHostA());
/* Set the output. */
*out = std::move(fsa);
R_SUCCEED();
}
Result PreMountHost(std::unique_ptr<fs::HostCommonMountNameGenerator> *out, const char *name, const char *path) {
/* Check pre-conditions. */
AMS_ASSERT(out != nullptr);
/* Check the mount name. */
R_TRY(impl::CheckMountName(name));
/* Check that path is valid. */
R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
/* Create a new HostCommonMountNameGenerator. */
*out = std::make_unique<HostCommonMountNameGenerator>(path);
R_UNLESS(out->get() != nullptr, fs::ResultAllocationMemoryFailedInHostB());
R_SUCCEED();
}
}
namespace impl {
Result OpenHostFileSystem(std::unique_ptr<fs::fsa::IFileSystem> *out, const char *name, const char *path, const fs::MountHostOption &option) {
/* Validate arguments. */
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
R_UNLESS(name != nullptr, fs::ResultNullptrArgument());
R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
/* Check mount name isn't windows path or reserved. */
R_UNLESS(!fs::IsWindowsDrive(name), fs::ResultInvalidMountName());
R_UNLESS(!fs::impl::IsReservedMountName(name), fs::ResultInvalidMountName());
/* Convert the path for fsp. */
fssrv::sf::FspPath sf_path;
R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path));
/* Ensure that the path doesn't correspond to the root. */
if (sf_path.str[0] == 0) {
sf_path.str[0] = '.';
sf_path.str[1] = 0;
}
/* Open the host file system. */
R_RETURN(OpenHostFileSystemImpl(out, sf_path, option));
}
}
Result MountHost(const char *name, const char *root_path) {
/* Pre-mount host. */
std::unique_ptr<fs::HostCommonMountNameGenerator> generator;
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(PreMountHost(std::addressof(generator), name, root_path), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST(name, root_path)));
/* Open the filesystem. */
std::unique_ptr<fs::fsa::IFileSystem> fsa;
R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(impl::OpenHostFileSystem(std::addressof(fsa), name, root_path, MountHostOption::None), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST(name, root_path)));
/* Declare registration helper. */
auto register_impl = [&]() -> Result {
/* Register. */
R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator)));
};
/* Mount the filesystem. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(register_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST(name, root_path)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
Result MountHost(const char *name, const char *root_path, const MountHostOption &option) {
/* Pre-mount host. */
std::unique_ptr<fs::HostCommonMountNameGenerator> generator;
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(PreMountHost(std::addressof(generator), name, root_path), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_WITH_OPTION(name, root_path, option)));
/* Open the filesystem. */
std::unique_ptr<fs::fsa::IFileSystem> fsa;
R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(impl::OpenHostFileSystem(std::addressof(fsa), name, root_path, option), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_WITH_OPTION(name, root_path, option)));
/* Declare registration helper. */
auto register_impl = [&]() -> Result {
/* Register. */
R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator)));
};
/* Mount the filesystem. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(register_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_WITH_OPTION(name, root_path, option)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
Result MountHostRoot() {
/* Create host root path. */
fssrv::sf::FspPath sf_path;
sf_path.str[0] = 0;
/* Open the filesystem. */
std::unique_ptr<fs::fsa::IFileSystem> fsa;
R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(OpenHostFileSystemImpl(std::addressof(fsa), sf_path, MountHostOption::None), impl::HostRootFileSystemMountName, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT()));
/* Declare registration helper. */
auto register_impl = [&]() -> Result {
/* Allocate a new mountname generator. */
auto generator = std::make_unique<HostRootCommonMountNameGenerator>();
R_UNLESS(generator != nullptr, fs::ResultAllocationMemoryFailedInHostC());
/* Register. */
R_RETURN(fsa::Register(impl::HostRootFileSystemMountName, std::move(fsa), std::move(generator)));
};
/* Mount the filesystem. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(register_impl(), impl::HostRootFileSystemMountName, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT()));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(impl::HostRootFileSystemMountName);
R_SUCCEED();
}
Result MountHostRoot(const MountHostOption &option) {
/* Create host root path. */
fssrv::sf::FspPath sf_path;
sf_path.str[0] = 0;
/* Open the filesystem. */
std::unique_ptr<fs::fsa::IFileSystem> fsa;
R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(OpenHostFileSystemImpl(std::addressof(fsa), sf_path, option), impl::HostRootFileSystemMountName, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT_WITH_OPTION(option)));
/* Declare registration helper. */
auto register_impl = [&]() -> Result {
/* Allocate a new mountname generator. */
auto generator = std::make_unique<HostRootCommonMountNameGenerator>();
R_UNLESS(generator != nullptr, fs::ResultAllocationMemoryFailedInHostC());
/* Register. */
R_RETURN(fsa::Register(impl::HostRootFileSystemMountName, std::move(fsa), std::move(generator)));
};
/* Mount the filesystem. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT(register_impl(), impl::HostRootFileSystemMountName, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT_WITH_OPTION(option)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(impl::HostRootFileSystemMountName);
R_SUCCEED();
}
void UnmountHostRoot() {
return Unmount(impl::HostRootFileSystemMountName);
}
}

View File

@@ -1,50 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
#include "impl/fs_file_system_service_object_adapter.hpp"
namespace ams::fs {
Result MountImageDirectory(const char *name, ImageDirectoryId id) {
auto mount_impl = [=]() -> Result {
/* Validate the mount name. */
R_TRY(impl::CheckMountName(name));
/* Open the image directory. */
auto fsp = impl::GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
R_TRY(fsp->OpenImageDirectoryFileSystem(std::addressof(fs), static_cast<u32>(id)));
/* Allocate a new filesystem wrapper. */
auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs));
R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInImageDirectoryA());
/* Register. */
R_RETURN(fsa::Register(name, std::move(fsa)));
};
/* Perform the mount. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_IMAGE_DIRECTORY(name, id)));
/* Enable access logging. */
AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
}

View File

@@ -1,119 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
namespace ams::fs {
namespace {
constinit bool g_used_default_allocator = false;
void *DefaultAllocate(size_t size) {
g_used_default_allocator = true;
return ams::Malloc(size);
}
void DefaultDeallocate(void *ptr, size_t size) {
AMS_UNUSED(size);
ams::Free(ptr);
}
constinit os::SdkMutex g_mutex;
constinit AllocateFunction g_allocate_func = DefaultAllocate;
constinit DeallocateFunction g_deallocate_func = DefaultDeallocate;
constexpr size_t RequiredAlignment = alignof(u64);
Result SetAllocatorImpl(AllocateFunction allocator, DeallocateFunction deallocator) {
/* Ensure SetAllocator is used correctly. */
R_UNLESS(g_allocate_func == DefaultAllocate, fs::ResultAllocatorAlreadyRegistered());
R_UNLESS(g_deallocate_func == DefaultDeallocate, fs::ResultAllocatorAlreadyRegistered());
R_UNLESS(allocator != nullptr, fs::ResultNullptrArgument());
R_UNLESS(deallocator != nullptr, fs::ResultNullptrArgument());
R_UNLESS(!g_used_default_allocator, fs::ResultDefaultAllocatorUsed());
/* Set allocators. */
g_allocate_func = allocator;
g_deallocate_func = deallocator;
R_SUCCEED();
}
}
void SetAllocator(AllocateFunction allocator, DeallocateFunction deallocator) {
R_ABORT_UNLESS(SetAllocatorImpl(allocator, deallocator));
}
namespace impl {
void LockAllocatorMutex() {
g_mutex.Lock();
}
void UnlockAllocatorMutex() {
g_mutex.Unlock();
}
void *AllocateUnsafe(size_t size) {
/* Check pre-conditions. */
AMS_ASSERT(g_mutex.IsLockedByCurrentThread());
/* Allocate. */
void * const ptr = g_allocate_func(size);
/* Check alignment. */
if (AMS_UNLIKELY(!util::IsAligned(reinterpret_cast<uintptr_t>(ptr), RequiredAlignment))) {
R_ABORT_UNLESS(fs::ResultAllocatorAlignmentViolation());
}
/* Return allocated pointer. */
return ptr;
}
void DeallocateUnsafe(void *ptr, size_t size) {
/* Check pre-conditions. */
AMS_ASSERT(g_mutex.IsLockedByCurrentThread());
/* Deallocate the pointer. */
g_deallocate_func(ptr, size);
}
void *Allocate(size_t size) {
/* Check pre-conditions. */
AMS_ASSERT(g_allocate_func != nullptr);
/* Lock the allocator. */
std::scoped_lock lk(g_mutex);
return AllocateUnsafe(size);
}
void Deallocate(void *ptr, size_t size) {
/* Check pre-conditions. */
AMS_ASSERT(g_deallocate_func != nullptr);
/* If the pointer is non-null, deallocate it. */
if (ptr != nullptr) {
/* Lock the allocator. */
std::scoped_lock lk(g_mutex);
DeallocateUnsafe(ptr, size);
}
}
}
}

View File

@@ -1,35 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
#include "impl/fs_file_system_service_object_adapter.hpp"
namespace ams::fs {
Result GetAndClearMemoryReportInfo(MemoryReportInfo *out) {
/* Check pre-conditions. */
AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Get the memory report info. */
AMS_FS_R_TRY(fsp->GetAndClearMemoryReportInfo(out));
R_SUCCEED();
}
}

View File

@@ -1,109 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
#include "impl/fs_file_system_service_object_adapter.hpp"
namespace ams::fs {
Result GetMmcCid(void *dst, size_t size) {
/* Check pre-conditions. */
AMS_FS_R_UNLESS(dst != nullptr, fs::ResultNullptrArgument());
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get the cid. */
AMS_FS_R_TRY(device_operator->GetMmcCid(sf::OutBuffer(dst, size), static_cast<s64>(size)));
R_SUCCEED();
}
Result GetMmcSpeedMode(MmcSpeedMode *out) {
/* Check pre-conditions. */
AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get the speed mode. */
s64 speed_mode = 0;
AMS_FS_R_TRY(device_operator->GetMmcSpeedMode(std::addressof(speed_mode)));
*out = static_cast<MmcSpeedMode>(speed_mode);
R_SUCCEED();
}
Result GetMmcPatrolCount(u32 *out) {
/* Check pre-conditions. */
AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get the patrol count. */
AMS_FS_R_TRY(device_operator->GetMmcPatrolCount(out));
R_SUCCEED();
}
Result GetAndClearMmcErrorInfo(StorageErrorInfo *out_sei, size_t *out_log_size, char *out_log_buffer, size_t log_buffer_size) {
/* Check pre-conditions. */
AMS_FS_R_UNLESS(out_sei != nullptr, fs::ResultNullptrArgument());
AMS_FS_R_UNLESS(out_log_size != nullptr, fs::ResultNullptrArgument());
AMS_FS_R_UNLESS(out_log_buffer != nullptr, fs::ResultNullptrArgument());
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get the error info. */
s64 log_size = 0;
AMS_FS_R_TRY(device_operator->GetAndClearMmcErrorInfo(out_sei, std::addressof(log_size), sf::OutBuffer(out_log_buffer, log_buffer_size), static_cast<s64>(log_buffer_size)));
*out_log_size = static_cast<size_t>(log_size);
R_SUCCEED();
}
Result GetMmcExtendedCsd(void *dst, size_t size) {
/* Check pre-conditions. */
AMS_FS_R_UNLESS(dst != nullptr, fs::ResultNullptrArgument());
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get the csd. */
AMS_FS_R_TRY(device_operator->GetMmcExtendedCsd(sf::OutBuffer(dst, size), static_cast<s64>(size)));
R_SUCCEED();
}
}

View File

@@ -1,160 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
namespace ams::fs {
namespace {
constexpr bool IsValidPriority(fs::Priority priority) {
return priority == Priority_Low || priority == Priority_Normal || priority == Priority_Realtime;
}
constexpr bool IsValidPriorityRaw(fs::PriorityRaw priority_raw) {
return priority_raw == PriorityRaw_Background || priority_raw == PriorityRaw_Low || priority_raw == PriorityRaw_Normal || priority_raw == PriorityRaw_Realtime;
}
fs::PriorityRaw ConvertPriorityToPriorityRaw(fs::Priority priority) {
AMS_ASSERT(IsValidPriority(priority));
switch (priority) {
case Priority_Low: return PriorityRaw_Low;
case Priority_Normal: return PriorityRaw_Normal;
case Priority_Realtime: return PriorityRaw_Realtime;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
fs::Priority ConvertPriorityRawToPriority(fs::PriorityRaw priority_raw) {
AMS_ASSERT(IsValidPriorityRaw(priority_raw));
switch (priority_raw) {
case PriorityRaw_Background: return Priority_Low;
case PriorityRaw_Low: return Priority_Low;
case PriorityRaw_Normal: return Priority_Normal;
case PriorityRaw_Realtime: return Priority_Realtime;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
void UpdateTlsIoPriority(os::ThreadType *thread, u8 tls_io) {
sf::SetFsInlineContext(thread, (tls_io & impl::TlsIoPriorityMask) | (sf::GetFsInlineContext(thread) & ~impl::TlsIoPriorityMask));
}
Result GetPriorityRawImpl(fs::PriorityRaw *out, os::ThreadType *thread) {
/* Validate arguments. */
R_UNLESS(thread != nullptr, fs::ResultNullptrArgument());
/* Get the raw priority. */
PriorityRaw priority_raw;
R_TRY(impl::ConvertTlsIoPriorityToFsPriority(std::addressof(priority_raw), impl::GetTlsIoPriority(thread)));
/* Set output. */
*out = priority_raw;
R_SUCCEED();
}
Result GetPriorityImpl(fs::Priority *out, os::ThreadType *thread) {
/* Validate arguments. */
R_UNLESS(thread != nullptr, fs::ResultNullptrArgument());
/* Get the raw priority. */
PriorityRaw priority_raw;
R_TRY(impl::ConvertTlsIoPriorityToFsPriority(std::addressof(priority_raw), impl::GetTlsIoPriority(thread)));
/* Set output. */
*out = ConvertPriorityRawToPriority(priority_raw);
R_SUCCEED();
}
Result SetPriorityRawImpl(os::ThreadType *thread, fs::PriorityRaw priority_raw) {
/* Validate arguments. */
R_UNLESS(thread != nullptr, fs::ResultNullptrArgument());
R_UNLESS(IsValidPriorityRaw(priority_raw), fs::ResultInvalidArgument());
/* Convert to tls io. */
u8 tls_io;
R_TRY(impl::ConvertFsPriorityToTlsIoPriority(std::addressof(tls_io), priority_raw));
/* Update the priority. */
UpdateTlsIoPriority(thread, tls_io);
R_SUCCEED();
}
Result SetPriorityImpl(os::ThreadType *thread, fs::Priority priority) {
/* Validate arguments. */
R_UNLESS(thread != nullptr, fs::ResultNullptrArgument());
R_UNLESS(IsValidPriority(priority), fs::ResultInvalidArgument());
/* Convert to tls io. */
u8 tls_io;
R_TRY(impl::ConvertFsPriorityToTlsIoPriority(std::addressof(tls_io), ConvertPriorityToPriorityRaw(priority)));
/* Update the priority. */
UpdateTlsIoPriority(thread, tls_io);
R_SUCCEED();
}
}
Priority GetPriorityOnCurrentThread() {
fs::Priority priority;
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityImpl(std::addressof(priority), os::GetCurrentThread()), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE));
return priority;
}
Priority GetPriority(os::ThreadType *thread) {
fs::Priority priority;
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityImpl(std::addressof(priority), thread), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, reinterpret_cast<u64>(thread != nullptr ? os::GetThreadId(thread) : os::ThreadId{})));
return priority;
}
PriorityRaw GetPriorityRawOnCurrentThread() {
fs::PriorityRaw priority_raw;
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityRawImpl(std::addressof(priority_raw), os::GetCurrentThread()), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE));
return priority_raw;
}
PriorityRaw GetPriorityRawOnCurrentThreadInternal() {
fs::PriorityRaw priority_raw;
R_ABORT_UNLESS(GetPriorityRawImpl(std::addressof(priority_raw), os::GetCurrentThread()));
return priority_raw;
}
PriorityRaw GetPriorityRaw(os::ThreadType *thread) {
fs::PriorityRaw priority_raw;
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(GetPriorityRawImpl(std::addressof(priority_raw), thread), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, reinterpret_cast<u64>(thread != nullptr ? os::GetThreadId(thread) : os::ThreadId{})));
return priority_raw;
}
void SetPriorityOnCurrentThread(Priority priority) {
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityImpl(os::GetCurrentThread(), priority), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE));
}
void SetPriority(os::ThreadType *thread, Priority priority) {
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityImpl(os::GetCurrentThread(), priority), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, reinterpret_cast<u64>(thread != nullptr ? os::GetThreadId(thread) : os::ThreadId{})));
}
void SetPriorityRawOnCurrentThread(PriorityRaw priority_raw) {
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityRawImpl(os::GetCurrentThread(), priority_raw), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE));
}
void SetPriorityRaw(os::ThreadType *thread, PriorityRaw priority_raw) {
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG(SetPriorityRawImpl(os::GetCurrentThread(), priority_raw), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID, reinterpret_cast<u64>(thread != nullptr ? os::GetThreadId(thread) : os::ThreadId{})));
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include <stratosphere/fs/fs_rights_id.hpp>
#include "impl/fs_file_system_proxy_service_object.hpp"
namespace ams::fs {
Result GetProgramId(ncm::ProgramId *out, const char *path, fs::ContentAttributes attr) {
AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
AMS_FS_R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
/* Convert the path for fsp. */
fssrv::sf::FspPath sf_path;
R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path));
auto fsp = impl::GetFileSystemProxyServiceObject();
AMS_FS_R_TRY(fsp->GetProgramId(out, sf_path, attr));
R_SUCCEED();
}
}

View File

@@ -1,58 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fs_remote_file_system_proxy.hpp"
#include "fs_remote_file_system_proxy_for_loader.hpp"
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
extern "C" {
extern u32 __nx_fs_num_sessions;
}
#endif
namespace ams::fs {
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
RemoteFileSystemProxy::RemoteFileSystemProxy(int session_count) {
/* Ensure we can connect to sm. */
R_ABORT_UNLESS(sm::Initialize());
ON_SCOPE_EXIT { R_ABORT_UNLESS(sm::Finalize()); };
/* Initialize libnx. */
__nx_fs_num_sessions = static_cast<u32>(session_count);
R_ABORT_UNLESS(::fsInitialize());
}
RemoteFileSystemProxy::~RemoteFileSystemProxy() {
::fsExit();
}
RemoteFileSystemProxyForLoader::RemoteFileSystemProxyForLoader() {
/* Ensure we can connect to sm. */
R_ABORT_UNLESS(sm::Initialize());
ON_SCOPE_EXIT { R_ABORT_UNLESS(sm::Finalize()); };
R_ABORT_UNLESS(::fsldrInitialize());
}
RemoteFileSystemProxyForLoader::~RemoteFileSystemProxyForLoader() {
::fsldrExit();
}
#endif
}

View File

@@ -1,492 +0,0 @@
/*
* Copyright (c) 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>
#include <stratosphere/fssrv/fssrv_interface_adapters.hpp>
#include "../fssrv/impl/fssrv_allocator_for_service_framework.hpp"
#include "impl/fs_remote_event_notifier.hpp"
#include "impl/fs_remote_device_operator.hpp"
namespace ams::fs {
#if defined(ATMOSPHERE_OS_HORIZON)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
class RemoteFileSystemProxy {
NON_COPYABLE(RemoteFileSystemProxy);
NON_MOVEABLE(RemoteFileSystemProxy);
private:
using ObjectFactory = fssrv::impl::FileSystemObjectFactory;
public:
RemoteFileSystemProxy(int session_count);
~RemoteFileSystemProxy();
public:
/* Command interface */
Result OpenFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 type) {
AMS_ABORT("TODO");
}
Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid) {
/* Libnx does this for us automatically. */
AMS_UNUSED(client_pid);
R_SUCCEED();
}
Result OpenDataFileSystemByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out) {
AMS_ABORT("TODO");
}
Result OpenFileSystemWithPatch(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 type) {
AMS_ABORT("TODO");
}
Result OpenFileSystemWithIdObsolete(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u64 program_id, u32 type) {
R_RETURN(this->OpenFileSystemWithId(out, path, fs::ContentAttributes_None, program_id, type));
}
Result OpenFileSystemWithId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u64 program_id, u32 type) {
::FsFileSystem fs;
R_TRY(fsOpenFileSystemWithId(std::addressof(fs), program_id, static_cast<::FsFileSystemType>(type), path.str, static_cast<::FsContentAttributes>(static_cast<u8>(attr))));
out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs));
R_SUCCEED();
}
Result OpenDataFileSystemByProgramId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id) {
AMS_ABORT("TODO");
}
Result OpenBisFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 id) {
AMS_ABORT("TODO");
}
Result OpenBisStorage(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 id) {
FsStorage s;
R_TRY(fsOpenBisStorage(std::addressof(s), static_cast<::FsBisPartitionId>(id)));
out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IStorage, fssrv::impl::RemoteStorage>(s));
R_SUCCEED();
}
Result InvalidateBisCache() {
AMS_ABORT("TODO");
}
Result OpenHostFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path) {
AMS_ABORT("TODO");
}
Result OpenSdCardFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out) {
::FsFileSystem fs;
R_TRY(fsOpenSdCardFileSystem(std::addressof(fs)));
out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs));
R_SUCCEED();
}
Result FormatSdCardFileSystem() {
AMS_ABORT("TODO");
}
Result DeleteSaveDataFileSystem(u64 save_data_id) {
AMS_UNUSED(save_data_id);
AMS_ABORT("TODO: libnx binding");
}
Result CreateSaveDataFileSystem(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info) {
AMS_ABORT("TODO");
}
Result CreateSaveDataFileSystemBySystemSaveDataId(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info) {
static_assert(sizeof(attribute) == sizeof(::FsSaveDataAttribute));
static_assert(sizeof(creation_info) == sizeof(::FsSaveDataCreationInfo));
R_RETURN(fsCreateSaveDataFileSystemBySystemSaveDataId(reinterpret_cast<const ::FsSaveDataAttribute *>(std::addressof(attribute)), reinterpret_cast<const ::FsSaveDataCreationInfo *>(std::addressof(creation_info))));
}
Result RegisterSaveDataFileSystemAtomicDeletion(const ams::sf::InBuffer &save_data_ids) {
AMS_ABORT("TODO");
}
Result DeleteSaveDataFileSystemBySaveDataSpaceId(u8 indexer_space_id, u64 save_data_id) {
R_RETURN(fsDeleteSaveDataFileSystemBySaveDataSpaceId(static_cast<::FsSaveDataSpaceId>(indexer_space_id), save_data_id));
}
Result FormatSdCardDryRun() {
AMS_ABORT("TODO");
}
Result IsExFatSupported(ams::sf::Out<bool> out) {
AMS_ABORT("TODO");
}
Result DeleteSaveDataFileSystemBySaveDataAttribute(u8 space_id, const fs::SaveDataAttribute &attribute) {
static_assert(sizeof(attribute) == sizeof(::FsSaveDataAttribute));
R_RETURN(fsDeleteSaveDataFileSystemBySaveDataAttribute(static_cast<::FsSaveDataSpaceId>(space_id), reinterpret_cast<const ::FsSaveDataAttribute *>(std::addressof(attribute))));
}
Result OpenGameCardStorage(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u32 handle, u32 partition) {
AMS_ABORT("TODO");
}
Result OpenGameCardFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 handle, u32 partition) {
::FsFileSystem fs;
const ::FsGameCardHandle _hnd = {handle};
R_TRY(fsOpenGameCardFileSystem(std::addressof(fs), std::addressof(_hnd), static_cast<::FsGameCardPartition>(partition)));
out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs));
R_SUCCEED();
}
Result ExtendSaveDataFileSystem(u8 space_id, u64 save_data_id, s64 available_size, s64 journal_size) {
R_RETURN(::fsExtendSaveDataFileSystem(static_cast<::FsSaveDataSpaceId>(space_id), save_data_id, available_size, journal_size));
}
Result DeleteCacheStorage(u16 index) {
AMS_ABORT("TODO");
}
Result GetCacheStorageSize(ams::sf::Out<s64> out_size, ams::sf::Out<s64> out_journal_size, u16 index) {
AMS_ABORT("TODO");
}
Result CreateSaveDataFileSystemWithHashSalt(const fs::SaveDataAttribute &attribute, const fs::SaveDataCreationInfo &creation_info, const fs::SaveDataMetaInfo &meta_info, const fs::HashSalt &salt) {
AMS_ABORT("TODO");
}
Result OpenHostFileSystemWithOption(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, const fssrv::sf::FspPath &path, u32 option) {
AMS_ABORT("TODO");
}
Result OpenSaveDataFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute) {
::FsFileSystem fs;
R_TRY(fsOpenSaveDataFileSystem(std::addressof(fs), static_cast<::FsSaveDataSpaceId>(space_id), reinterpret_cast<const ::FsSaveDataAttribute *>(std::addressof(attribute))));
out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs));
R_SUCCEED();
}
Result OpenSaveDataFileSystemBySystemSaveDataId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute) {
::FsFileSystem fs;
R_TRY(fsOpenSaveDataFileSystemBySystemSaveDataId(std::addressof(fs), static_cast<::FsSaveDataSpaceId>(space_id), reinterpret_cast<const ::FsSaveDataAttribute *>(std::addressof(attribute))));
out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs));
R_SUCCEED();
}
Result OpenReadOnlySaveDataFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 space_id, const fs::SaveDataAttribute &attribute) {
AMS_ABORT("TODO");
}
Result ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(const ams::sf::OutBuffer &buffer, u8 space_id, u64 save_data_id) {
R_RETURN(fsReadSaveDataFileSystemExtraDataBySaveDataSpaceId(buffer.GetPointer(), buffer.GetSize(), static_cast<::FsSaveDataSpaceId>(space_id), save_data_id));
}
Result ReadSaveDataFileSystemExtraData(const ams::sf::OutBuffer &buffer, u64 save_data_id) {
R_RETURN(fsReadSaveDataFileSystemExtraData(buffer.GetPointer(), buffer.GetSize(), save_data_id));
}
Result WriteSaveDataFileSystemExtraData(u64 save_data_id, u8 space_id, const ams::sf::InBuffer &buffer) {
R_RETURN(fsWriteSaveDataFileSystemExtraData(buffer.GetPointer(), buffer.GetSize(), static_cast<::FsSaveDataSpaceId>(space_id), save_data_id));
}
/* ... */
Result OpenImageDirectoryFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 id) {
::FsFileSystem fs;
R_TRY(fsOpenImageDirectoryFileSystem(std::addressof(fs), static_cast<::FsImageDirectoryId>(id)));
out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs));
R_SUCCEED();
}
/* ... */
Result OpenContentStorageFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u32 id) {
::FsFileSystem fs;
R_TRY(fsOpenContentStorageFileSystem(std::addressof(fs), static_cast<::FsContentStorageId>(id)));
out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs));
R_SUCCEED();
}
/* ... */
Result OpenDataStorageByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out) {
AMS_ABORT("TODO");
}
Result OpenDataStorageByProgramId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, ncm::ProgramId program_id) {
AMS_ABORT("TODO");
}
Result OpenDataStorageByDataId(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, ncm::DataId data_id, u8 storage_id) {
::FsStorage s;
R_TRY(fsOpenDataStorageByDataId(std::addressof(s), data_id.value, static_cast<::NcmStorageId>(storage_id)));
out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IStorage, fssrv::impl::RemoteStorage>(s));
R_SUCCEED();
}
Result OpenPatchDataStorageByCurrentProcess(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out) {
AMS_ABORT("TODO");
}
Result OpenDataFileSystemWithProgramIndex(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out, u8 index) {
AMS_ABORT("TODO");
}
Result OpenDataStorageWithProgramIndex(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, u8 index) {
AMS_ABORT("TODO");
}
Result OpenDataStorageByPathObsolete(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, u32 type) {
AMS_ABORT("TODO");
}
Result OpenDataStorageByPath(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IStorage>> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr, u32 type) {
AMS_ABORT("TODO");
}
Result OpenDeviceOperator(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IDeviceOperator>> out) {
::FsDeviceOperator d;
R_TRY(fsOpenDeviceOperator(std::addressof(d)));
out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IDeviceOperator, impl::RemoteDeviceOperator>(d));
R_SUCCEED();
}
Result OpenSdCardDetectionEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out) {
::FsEventNotifier e;
R_TRY(fsOpenSdCardDetectionEventNotifier(std::addressof(e)));
out.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IEventNotifier, impl::RemoteEventNotifier>(e));
R_SUCCEED();
}
Result OpenGameCardDetectionEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out) {
AMS_ABORT("TODO");
}
Result OpenSystemDataUpdateEventNotifier(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IEventNotifier>> out) {
AMS_ABORT("TODO");
}
Result NotifySystemDataUpdateEvent() {
AMS_ABORT("TODO");
}
/* ... */
Result SetCurrentPosixTime(s64 posix_time) {
AMS_ABORT("TODO");
}
/* ... */
Result GetRightsId(ams::sf::Out<fs::RightsId> out, ncm::ProgramId program_id, ncm::StorageId storage_id) {
AMS_ABORT("TODO");
}
Result RegisterExternalKey(const fs::RightsId &rights_id, const spl::AccessKey &access_key) {
AMS_ABORT("TODO");
}
Result UnregisterAllExternalKey() {
AMS_ABORT("TODO");
}
Result GetProgramId(ams::sf::Out<ncm::ProgramId> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr) {
static_assert(sizeof(ncm::ProgramId) == sizeof(u64));
R_RETURN(fsGetProgramId(reinterpret_cast<u64 *>(out.GetPointer()), path.str, static_cast<::FsContentAttributes>(static_cast<u8>(attr))));
}
Result GetRightsIdByPath(ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path) {
static_assert(sizeof(RightsId) == sizeof(::FsRightsId));
R_RETURN(fsGetRightsIdByPath(path.str, reinterpret_cast<::FsRightsId *>(out.GetPointer())));
}
Result GetRightsIdAndKeyGenerationByPathObsolete(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path) {
R_RETURN(this->GetRightsIdAndKeyGenerationByPath(out, out_key_generation, path, fs::ContentAttributes_None))
}
Result GetRightsIdAndKeyGenerationByPath(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path, fs::ContentAttributes attr) {
static_assert(sizeof(RightsId) == sizeof(::FsRightsId));
R_RETURN(fsGetRightsIdAndKeyGenerationByPath(path.str, static_cast<::FsContentAttributes>(static_cast<u8>(attr)), out_key_generation.GetPointer(), reinterpret_cast<::FsRightsId *>(out.GetPointer())));
}
Result SetCurrentPosixTimeWithTimeDifference(s64 posix_time, s32 time_difference) {
AMS_ABORT("TODO");
}
Result GetFreeSpaceSizeForSaveData(ams::sf::Out<s64> out, u8 space_id) {
AMS_ABORT("TODO");
}
Result VerifySaveDataFileSystemBySaveDataSpaceId() {
AMS_ABORT("TODO");
}
Result CorruptSaveDataFileSystemBySaveDataSpaceId() {
AMS_ABORT("TODO");
}
Result QuerySaveDataInternalStorageTotalSize() {
AMS_ABORT("TODO");
}
Result GetSaveDataCommitId() {
AMS_ABORT("TODO");
}
Result UnregisterExternalKey(const fs::RightsId &rights_id) {
AMS_ABORT("TODO");
}
Result SetSdCardEncryptionSeed(const fs::EncryptionSeed &seed) {
AMS_ABORT("TODO");
}
Result SetSdCardAccessibility(bool accessible) {
AMS_ABORT("TODO");
}
Result IsSdCardAccessible(ams::sf::Out<bool> out) {
AMS_ABORT("TODO");
}
Result IsSignedSystemPartitionOnSdCardValid(ams::sf::Out<bool> out) {
R_RETURN(fsIsSignedSystemPartitionOnSdCardValid(out.GetPointer()));
}
Result OpenAccessFailureDetectionEventNotifier() {
AMS_ABORT("TODO");
}
/* ... */
Result GetAndClearErrorInfo(ams::sf::Out<fs::FileSystemProxyErrorInfo> out) {
static_assert(sizeof(fs::FileSystemProxyErrorInfo) == sizeof(::FsFileSystemProxyErrorInfo));
R_RETURN(::fsGetAndClearErrorInfo(reinterpret_cast<::FsFileSystemProxyErrorInfo *>(out.GetPointer())));
}
Result RegisterProgramIndexMapInfo(const ams::sf::InBuffer &buffer, s32 count) {
AMS_ABORT("TODO");
}
Result SetBisRootForHost(u32 id, const fssrv::sf::FspPath &path) {
AMS_ABORT("TODO");
}
Result SetSaveDataSize(s64 size, s64 journal_size) {
AMS_ABORT("TODO");
}
Result SetSaveDataRootPath(const fssrv::sf::FspPath &path) {
AMS_ABORT("TODO");
}
Result DisableAutoSaveDataCreation() {
R_RETURN(::fsDisableAutoSaveDataCreation());
}
Result SetGlobalAccessLogMode(u32 mode) {
R_RETURN(::fsSetGlobalAccessLogMode(mode));
}
Result GetGlobalAccessLogMode(sf::Out<u32> out) {
R_RETURN(::fsGetGlobalAccessLogMode(out.GetPointer()));
}
Result OutputAccessLogToSdCard(const ams::sf::InBuffer &buf) {
R_RETURN(::fsOutputAccessLogToSdCard(reinterpret_cast<const char *>(buf.GetPointer()), buf.GetSize()));
}
Result RegisterUpdatePartition() {
AMS_ABORT("TODO");
}
Result OpenRegisteredUpdatePartition(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out) {
AMS_ABORT("TODO");
}
Result GetAndClearMemoryReportInfo(ams::sf::Out<fs::MemoryReportInfo> out) {
static_assert(sizeof(fs::MemoryReportInfo) == sizeof(::FsMemoryReportInfo));
R_RETURN(::fsGetAndClearMemoryReportInfo(reinterpret_cast<::FsMemoryReportInfo *>(out.GetPointer())));
}
/* ... */
Result GetProgramIndexForAccessLog(ams::sf::Out<u32> out_idx, ams::sf::Out<u32> out_count) {
R_RETURN(::fsGetProgramIndexForAccessLog(out_idx.GetPointer(), out_count.GetPointer()));
}
Result GetFsStackUsage(ams::sf::Out<u32> out, u32 type) {
AMS_ABORT("TODO");
}
Result UnsetSaveDataRootPath() {
AMS_ABORT("TODO");
}
Result OutputMultiProgramTagAccessLog() {
AMS_ABORT("TODO");
}
Result FlushAccessLogOnSdCard() {
AMS_ABORT("TODO");
}
Result OutputApplicationInfoAccessLog() {
AMS_ABORT("TODO");
}
Result RegisterDebugConfiguration(u32 key, s64 value) {
AMS_ABORT("TODO");
}
Result UnregisterDebugConfiguration(u32 key) {
AMS_ABORT("TODO");
}
Result OverrideSaveDataTransferTokenSignVerificationKey(const ams::sf::InBuffer &buf) {
AMS_ABORT("TODO");
}
Result CorruptSaveDataFileSystemByOffset(u8 space_id, u64 save_data_id, s64 offset) {
AMS_ABORT("TODO");
}
/* ... */
};
static_assert(fssrv::sf::IsIFileSystemProxy<RemoteFileSystemProxy>);
#pragma GCC diagnostic pop
#endif
}

View File

@@ -1,87 +0,0 @@
/*
* Copyright (c) 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>
#include <stratosphere/fssrv/fssrv_interface_adapters.hpp>
#include "../fssrv/impl/fssrv_allocator_for_service_framework.hpp"
namespace ams::fs {
#if defined(ATMOSPHERE_OS_HORIZON)
class RemoteFileSystemProxyForLoader {
NON_COPYABLE(RemoteFileSystemProxyForLoader);
NON_MOVEABLE(RemoteFileSystemProxyForLoader);
private:
using ObjectFactory = fssrv::impl::FileSystemObjectFactory;
public:
RemoteFileSystemProxyForLoader();
~RemoteFileSystemProxyForLoader();
public:
Result OpenCodeFileSystemDeprecated(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id) {
::FsCodeInfo dummy;
::FsFileSystem fs;
R_TRY(fsldrOpenCodeFileSystem(std::addressof(dummy), program_id.value, ::NcmStorageId_None, path.str, static_cast<::FsContentAttributes>(static_cast<u8>(fs::ContentAttributes_None)), std::addressof(fs)));
out_fs.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs));
R_SUCCEED();
}
Result OpenCodeFileSystemDeprecated2(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id) {
::FsFileSystem fs;
R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_verif.GetPointer()), program_id.value, ::NcmStorageId_None, path.str, static_cast<::FsContentAttributes>(static_cast<u8>(fs::ContentAttributes_None)), std::addressof(fs)));
out_fs.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs));
R_SUCCEED();
}
Result OpenCodeFileSystemDeprecated3(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) {
::FsFileSystem fs;
R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_verif.GetPointer()), program_id.value, ::NcmStorageId_None, path.str, static_cast<::FsContentAttributes>(static_cast<u8>(attr)), std::addressof(fs)));
out_fs.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs));
R_SUCCEED();
}
Result OpenCodeFileSystemDeprecated4(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) {
::FsFileSystem fs;
R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_verif.GetPointer()), program_id.value, ::NcmStorageId_None, path.str, static_cast<::FsContentAttributes>(static_cast<u8>(attr)), std::addressof(fs)));
out_fs.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs));
R_SUCCEED();
}
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, fs::ContentAttributes attr, ncm::ProgramId program_id, ncm::StorageId storage_id) {
::FsFileSystem fs;
R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_verif.GetPointer()), program_id.value, static_cast<::NcmStorageId>(static_cast<u8>(storage_id)), nullptr, static_cast<::FsContentAttributes>(static_cast<u8>(attr)), std::addressof(fs)));
out_fs.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs));
R_SUCCEED();
}
Result IsArchivedProgram(ams::sf::Out<bool> out, u64 process_id) {
R_RETURN(fsldrIsArchivedProgram(process_id, out.GetPointer()));
}
Result SetCurrentProcess(const ams::sf::ClientProcessId &client_pid) {
/* Libnx does this for us automatically. */
AMS_UNUSED(client_pid);
R_SUCCEED();
}
};
static_assert(fssrv::sf::IsIFileSystemProxyForLoader<RemoteFileSystemProxyForLoader>);
#endif
}

View File

@@ -1,71 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
namespace ams::fs {
namespace {
constinit bool g_handled_by_application = false;
}
void SetResultHandledByApplication(bool application) {
g_handled_by_application = application;
}
namespace impl {
bool IsAbortNeeded(Result result) {
/* If the result succeeded, we never need to abort. */
if (R_SUCCEEDED(result)) {
return false;
}
/* Get the abort specifier from current context. */
switch (GetCurrentThreadFsContext()->HandleResult(result)) {
case AbortSpecifier::Default:
if (g_handled_by_application) {
return !fs::ResultHandledByAllProcess::Includes(result);
} else {
return !(fs::ResultHandledByAllProcess::Includes(result) || fs::ResultHandledBySystemProcess::Includes(result));
}
case AbortSpecifier::Abort:
return true;
case AbortSpecifier::Return:
return false;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
void LogResultErrorMessage(Result result) {
/* TODO: log specific results */
AMS_UNUSED(result);
}
void LogErrorMessage(Result result, const char *function) {
/* If the result succeeded, there's nothing to log. */
if (R_SUCCEEDED(result)) {
return;
}
/* TODO: Actually log stuff. */
AMS_UNUSED(function);
}
}
}

View File

@@ -1,57 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include <stratosphere/fs/fs_rights_id.hpp>
#include "impl/fs_file_system_proxy_service_object.hpp"
namespace ams::fs {
Result GetRightsId(RightsId *out, const char *path, fs::ContentAttributes attr) {
/* If possible, prefer the non-removed functionality. */
if (hos::GetVersion() >= hos::Version_3_0_0) {
u8 dummy_key_generation;
R_RETURN(GetRightsId(out, std::addressof(dummy_key_generation), path, attr));
}
AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
AMS_FS_R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
/* Convert the path for fsp. */
fssrv::sf::FspPath sf_path;
R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path));
auto fsp = impl::GetFileSystemProxyServiceObject();
AMS_FS_R_TRY(fsp->GetRightsIdByPath(out, sf_path));
R_SUCCEED();
}
Result GetRightsId(RightsId *out, u8 *out_key_generation, const char *path, fs::ContentAttributes attr) {
AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
AMS_FS_R_UNLESS(out_key_generation != nullptr, fs::ResultNullptrArgument());
AMS_FS_R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
/* Convert the path for fsp. */
fssrv::sf::FspPath sf_path;
R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path));
auto fsp = impl::GetFileSystemProxyServiceObject();
AMS_FS_R_TRY(fsp->GetRightsIdAndKeyGenerationByPath(out, out_key_generation, sf_path, attr));
R_SUCCEED();
}
}

View File

@@ -1,558 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
namespace ams::fs {
namespace {
Result ConvertNcaCorruptedResult(Result res) {
AMS_ASSERT(fs::ResultNcaCorrupted::Includes(res));
R_TRY_CATCH(res) {
R_CONVERT(fs::ResultInvalidNcaFileSystemType, fs::ResultInvalidRomNcaFileSystemType())
R_CONVERT(fs::ResultInvalidAcidFileSize, fs::ResultInvalidRomAcidFileSize())
R_CONVERT(fs::ResultInvalidAcidSize, fs::ResultInvalidRomAcidSize())
R_CONVERT(fs::ResultInvalidAcid, fs::ResultInvalidRomAcid())
R_CONVERT(fs::ResultAcidVerificationFailed, fs::ResultRomAcidVerificationFailed())
R_CONVERT(fs::ResultInvalidNcaSignature, fs::ResultInvalidRomNcaSignature())
R_CONVERT(fs::ResultNcaHeaderSignature1VerificationFailed, fs::ResultRomNcaHeaderSignature1VerificationFailed())
R_CONVERT(fs::ResultNcaHeaderSignature2VerificationFailed, fs::ResultRomNcaHeaderSignature2VerificationFailed())
R_CONVERT(fs::ResultNcaFsHeaderHashVerificationFailed, fs::ResultRomNcaFsHeaderHashVerificationFailed())
R_CONVERT(fs::ResultInvalidNcaKeyIndex, fs::ResultInvalidRomNcaKeyIndex())
R_CONVERT(fs::ResultInvalidNcaFsHeaderHashType, fs::ResultInvalidRomNcaFsHeaderHashType())
R_CONVERT(fs::ResultInvalidNcaFsHeaderEncryptionType, fs::ResultInvalidRomNcaFsHeaderEncryptionType())
R_CONVERT(fs::ResultInvalidHierarchicalSha256BlockSize, fs::ResultInvalidRomHierarchicalSha256BlockSize())
R_CONVERT(fs::ResultInvalidHierarchicalSha256LayerCount, fs::ResultInvalidRomHierarchicalSha256LayerCount())
R_CONVERT(fs::ResultHierarchicalSha256BaseStorageTooLarge, fs::ResultRomHierarchicalSha256BaseStorageTooLarge())
R_CONVERT(fs::ResultHierarchicalSha256HashVerificationFailed, fs::ResultRomHierarchicalSha256HashVerificationFailed())
R_CATCH_ALL() { /* ... */ }
} R_END_TRY_CATCH;
AMS_ASSERT(false);
R_THROW(fs::ResultNcaCorrupted());
}
Result ConvertIntegrityVerificationStorageCorruptedResult(Result res) {
AMS_ASSERT(fs::ResultIntegrityVerificationStorageCorrupted::Includes(res));
R_TRY_CATCH(res) {
R_CONVERT(fs::ResultIncorrectIntegrityVerificationMagic, fs::ResultIncorrectRomIntegrityVerificationMagic())
R_CONVERT(fs::ResultInvalidZeroHash, fs::ResultInvalidRomZeroHash())
R_CONVERT(fs::ResultNonRealDataVerificationFailed, fs::ResultRomNonRealDataVerificationFailed())
R_CONVERT(fs::ResultInvalidHierarchicalIntegrityVerificationLayerCount, fs::ResultInvalidRomHierarchicalIntegrityVerificationLayerCount())
R_CONVERT(fs::ResultClearedRealDataVerificationFailed, fs::ResultClearedRomRealDataVerificationFailed())
R_CONVERT(fs::ResultUnclearedRealDataVerificationFailed, fs::ResultUnclearedRomRealDataVerificationFailed())
R_CATCH_ALL() { /* ... */ }
} R_END_TRY_CATCH;
AMS_ASSERT(false);
R_THROW(fs::ResultIntegrityVerificationStorageCorrupted());
}
Result ConvertBuiltInStorageCorruptedResult(Result res) {
AMS_ASSERT(fs::ResultBuiltInStorageCorrupted::Includes(res));
R_TRY_CATCH(res) {
R_CONVERT(fs::ResultGptHeaderVerificationFailed, fs::ResultRomGptHeaderVerificationFailed())
R_CATCH_ALL() { /* ... */ }
} R_END_TRY_CATCH;
AMS_ASSERT(false);
R_THROW(fs::ResultBuiltInStorageCorrupted());
}
Result ConvertPartitionFileSystemCorruptedResult(Result res) {
AMS_ASSERT(fs::ResultPartitionFileSystemCorrupted::Includes(res));
R_TRY_CATCH(res) {
R_CONVERT(fs::ResultInvalidSha256PartitionHashTarget, fs::ResultInvalidRomSha256PartitionHashTarget())
R_CONVERT(fs::ResultSha256PartitionHashVerificationFailed, fs::ResultRomSha256PartitionHashVerificationFailed())
R_CONVERT(fs::ResultPartitionSignatureVerificationFailed, fs::ResultRomPartitionSignatureVerificationFailed())
R_CONVERT(fs::ResultSha256PartitionSignatureVerificationFailed, fs::ResultRomSha256PartitionSignatureVerificationFailed())
R_CONVERT(fs::ResultInvalidPartitionEntryOffset, fs::ResultInvalidRomPartitionEntryOffset())
R_CONVERT(fs::ResultInvalidSha256PartitionMetaDataSize, fs::ResultInvalidRomSha256PartitionMetaDataSize())
R_CATCH_ALL() { /* ... */ }
} R_END_TRY_CATCH;
AMS_ASSERT(false);
R_THROW(fs::ResultPartitionFileSystemCorrupted());
}
Result ConvertFatFileSystemCorruptedResult(Result res) {
AMS_ASSERT(fs::ResultFatFileSystemCorrupted::Includes(res));
R_RETURN(res);
}
Result ConvertHostFileSystemCorruptedResult(Result res) {
AMS_ASSERT(fs::ResultHostFileSystemCorrupted::Includes(res));
R_TRY_CATCH(res) {
R_CONVERT(fs::ResultHostEntryCorrupted, fs::ResultRomHostEntryCorrupted())
R_CONVERT(fs::ResultHostFileDataCorrupted, fs::ResultRomHostFileDataCorrupted())
R_CONVERT(fs::ResultHostFileCorrupted, fs::ResultRomHostFileCorrupted())
R_CONVERT(fs::ResultInvalidHostHandle, fs::ResultInvalidRomHostHandle())
R_CATCH_ALL() { /* ... */ }
} R_END_TRY_CATCH;
AMS_ASSERT(false);
R_THROW(fs::ResultHostFileSystemCorrupted());
}
Result ConvertDatabaseCorruptedResult(Result res) {
AMS_ASSERT(fs::ResultDatabaseCorrupted::Includes(res));
R_TRY_CATCH(res) {
R_CONVERT(fs::ResultInvalidAllocationTableBlock, fs::ResultInvalidRomAllocationTableBlock())
R_CONVERT(fs::ResultInvalidKeyValueListElementIndex, fs::ResultInvalidRomKeyValueListElementIndex())
R_CATCH_ALL() { /* ... */ }
} R_END_TRY_CATCH;
AMS_ASSERT(false);
R_THROW(fs::ResultDatabaseCorrupted());
}
Result ConvertRomFsResult(Result res) {
R_TRY_CATCH(res) {
R_CONVERT(fs::ResultUnsupportedVersion, fs::ResultUnsupportedRomVersion())
R_CONVERT(fs::ResultNcaCorrupted, ConvertNcaCorruptedResult(res))
R_CONVERT(fs::ResultIntegrityVerificationStorageCorrupted, ConvertIntegrityVerificationStorageCorruptedResult(res))
R_CONVERT(fs::ResultBuiltInStorageCorrupted, ConvertBuiltInStorageCorruptedResult(res))
R_CONVERT(fs::ResultPartitionFileSystemCorrupted, ConvertPartitionFileSystemCorruptedResult(res))
R_CONVERT(fs::ResultFatFileSystemCorrupted, ConvertFatFileSystemCorruptedResult(res))
R_CONVERT(fs::ResultHostFileSystemCorrupted, ConvertHostFileSystemCorruptedResult(res))
R_CONVERT(fs::ResultDatabaseCorrupted, ConvertDatabaseCorruptedResult(res))
R_CONVERT(fs::ResultNotFound, fs::ResultPathNotFound())
R_CONVERT(fs::ResultPermissionDenied, fs::ResultTargetLocked())
R_CONVERT(fs::ResultIncompatiblePath, fs::ResultPathNotFound())
} R_END_TRY_CATCH;
R_SUCCEED();
}
Result ReadFile(IStorage *storage, s64 offset, void *buffer, size_t size) {
AMS_ASSERT(storage != nullptr);
AMS_ASSERT(offset >= 0);
AMS_ASSERT(buffer != nullptr || size == 0);
R_RETURN(ConvertRomFsResult(storage->Read(offset, buffer, size)));
}
Result ReadFileHeader(IStorage *storage, RomFileSystemInformation *out) {
AMS_ASSERT(storage != nullptr);
AMS_ASSERT(out != nullptr);
R_RETURN(ReadFile(storage, 0, out, sizeof(*out)));
}
constexpr size_t CalculateRequiredWorkingMemorySize(const RomFileSystemInformation &header) {
const size_t needed_size = header.directory_bucket_size + header.directory_entry_size + header.file_bucket_size + header.file_entry_size;
return util::AlignUp(needed_size, 8);
}
class RomFsFile : public fsa::IFile, public impl::Newable {
private:
RomFsFileSystem *m_parent;
s64 m_start;
s64 m_end;
public:
RomFsFile(RomFsFileSystem *p, s64 s, s64 e) : m_parent(p), m_start(s), m_end(e) { /* ... */ }
virtual ~RomFsFile() { /* ... */ }
Result VerifyArguments(size_t *out, s64 offset, void *buf, size_t size, const fs::ReadOption &option) {
R_TRY(DryRead(out, offset, size, option, fs::OpenMode_Read));
AMS_ASSERT(this->GetStorage() != nullptr);
AMS_ASSERT(offset >= 0);
AMS_ASSERT(buf != nullptr || size == 0);
AMS_UNUSED(buf);
R_SUCCEED();
}
Result ConvertResult(Result res) const {
R_RETURN(ConvertRomFsResult(res));
}
s64 GetOffset() const {
return m_start;
}
s64 GetSize() const {
return m_end - m_start;
}
IStorage *GetStorage() {
return m_parent->GetBaseStorage();
}
public:
virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override {
size_t read_size = 0;
R_TRY(this->VerifyArguments(std::addressof(read_size), offset, buffer, size, option));
R_TRY(this->ConvertResult(this->GetStorage()->Read(offset + m_start, buffer, size)));
*out = read_size;
R_SUCCEED();
}
virtual Result DoGetSize(s64 *out) override {
*out = this->GetSize();
R_SUCCEED();
}
virtual Result DoFlush() override {
R_SUCCEED();
}
virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override {
AMS_UNUSED(offset, buffer, size, option);
R_THROW(fs::ResultUnsupportedWriteForRomFsFile());
}
virtual Result DoSetSize(s64 size) override {
AMS_UNUSED(size);
R_THROW(fs::ResultUnsupportedWriteForRomFsFile());
}
virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
switch (op_id) {
case OperationId::Invalidate:
R_RETURN(this->GetStorage()->OperateRange(fs::OperationId::Invalidate, 0, std::numeric_limits<s64>::max()));
case OperationId::QueryRange:
{
R_UNLESS(offset >= 0, fs::ResultInvalidOffset());
R_UNLESS(this->GetSize() >= offset, fs::ResultOutOfRange());
auto operate_size = size;
if (offset + operate_size > this->GetSize() || offset + operate_size < offset) {
operate_size = this->GetSize() - offset;
}
R_RETURN(this->GetStorage()->OperateRange(dst, dst_size, op_id, m_start + offset, operate_size, src, src_size));
}
default:
R_THROW(fs::ResultUnsupportedOperateRangeForRomFsFile());
}
}
public:
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override {
AMS_ABORT();
}
};
class RomFsDirectory : public fsa::IDirectory, public impl::Newable {
private:
using FindPosition = RomFsFileSystem::RomFileTable::FindPosition;
private:
RomFsFileSystem *m_parent;
FindPosition m_current_find;
FindPosition m_first_find;
fs::OpenDirectoryMode m_mode;
public:
RomFsDirectory(RomFsFileSystem *p, const FindPosition &f, fs::OpenDirectoryMode m) : m_parent(p), m_current_find(f), m_first_find(f), m_mode(m) { /* ... */ }
virtual ~RomFsDirectory() override { /* ... */ }
public:
virtual Result DoRead(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override {
R_RETURN(this->ReadInternal(out_count, std::addressof(m_current_find), out_entries, max_entries));
}
virtual Result DoGetEntryCount(s64 *out) override {
FindPosition find = m_first_find;
R_RETURN(this->ReadInternal(out, std::addressof(find), nullptr, 0));
}
private:
Result ReadInternal(s64 *out_count, FindPosition *find, DirectoryEntry *out_entries, s64 max_entries) {
AMS_ASSERT(out_count != nullptr);
AMS_ASSERT(find != nullptr);
constexpr size_t NameBufferSize = fs::EntryNameLengthMax + 1;
char *name_buf = static_cast<char *>(::ams::fs::impl::Allocate(NameBufferSize));
R_UNLESS(name_buf != nullptr, fs::ResultAllocationMemoryFailedInRomFsFileSystemE());
ON_SCOPE_EXIT { ::ams::fs::impl::Deallocate(name_buf, NameBufferSize); };
s32 i = 0;
if (m_mode & fs::OpenDirectoryMode_Directory) {
while (i < max_entries || out_entries == nullptr) {
R_TRY_CATCH(m_parent->GetRomFileTable()->FindNextDirectory(name_buf, find, NameBufferSize)) {
R_CATCH(fs::ResultDbmFindFinished) { break; }
} R_END_TRY_CATCH;
if (out_entries) {
const size_t name_len = util::Strnlen(name_buf, NameBufferSize);
R_UNLESS(name_len < NameBufferSize, fs::ResultTooLongPath());
std::memcpy(out_entries[i].name, name_buf, name_len);
out_entries[i].name[name_len] = '\x00';
out_entries[i].type = fs::DirectoryEntryType_Directory;
out_entries[i].file_size = 0;
}
i++;
}
}
if (m_mode & fs::OpenDirectoryMode_File) {
while (i < max_entries || out_entries == nullptr) {
auto file_pos = find->next_file;
R_TRY_CATCH(m_parent->GetRomFileTable()->FindNextFile(name_buf, find, NameBufferSize)) {
R_CATCH(fs::ResultDbmFindFinished) { break; }
} R_END_TRY_CATCH;
if (out_entries) {
const size_t name_len = util::Strnlen(name_buf, NameBufferSize);
R_UNLESS(name_len < NameBufferSize, fs::ResultTooLongPath());
std::memcpy(out_entries[i].name, name_buf, name_len);
out_entries[i].name[name_len] = '\x00';
out_entries[i].type = fs::DirectoryEntryType_File;
RomFsFileSystem::RomFileTable::FileInfo file_info;
R_TRY(m_parent->GetRomFileTable()->OpenFile(std::addressof(file_info), m_parent->GetRomFileTable()->PositionToFileId(file_pos)));
out_entries[i].file_size = file_info.size.Get();
}
i++;
}
}
*out_count = i;
R_SUCCEED();
}
public:
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override {
AMS_ABORT();
}
};
}
RomFsFileSystem::RomFsFileSystem() : m_base_storage() {
/* ... */
}
RomFsFileSystem::~RomFsFileSystem() {
/* ... */
}
Result RomFsFileSystem::GetRequiredWorkingMemorySize(size_t *out, IStorage *storage) {
RomFileSystemInformation header;
R_TRY(ReadFileHeader(storage, std::addressof(header)));
*out = CalculateRequiredWorkingMemorySize(header);
R_SUCCEED();
}
Result RomFsFileSystem::Initialize(IStorage *base, void *work, size_t work_size, bool use_cache) {
AMS_ABORT_UNLESS(!use_cache || work != nullptr);
AMS_ABORT_UNLESS(base != nullptr);
/* Read the header. */
RomFileSystemInformation header;
R_TRY(ReadFileHeader(base, std::addressof(header)));
/* Set up our storages. */
if (use_cache) {
const size_t needed_size = CalculateRequiredWorkingMemorySize(header);
R_UNLESS(work_size >= needed_size, fs::ResultPreconditionViolation());
u8 *buf = static_cast<u8 *>(work);
auto dir_bucket_buf = buf; buf += header.directory_bucket_size;
auto dir_entry_buf = buf; buf += header.directory_entry_size;
auto file_bucket_buf = buf; buf += header.file_bucket_size;
auto file_entry_buf = buf; buf += header.file_entry_size;
R_TRY(ReadFile(base, header.directory_bucket_offset, dir_bucket_buf, header.directory_bucket_size));
R_TRY(ReadFile(base, header.directory_entry_offset, dir_entry_buf, header.directory_entry_size));
R_TRY(ReadFile(base, header.file_bucket_offset, file_bucket_buf, header.file_bucket_size));
R_TRY(ReadFile(base, header.file_entry_offset, file_entry_buf, header.file_entry_size));
m_dir_bucket_storage.reset(new MemoryStorage(dir_bucket_buf, header.directory_bucket_size));
m_dir_entry_storage.reset(new MemoryStorage(dir_entry_buf, header.directory_entry_size));
m_file_bucket_storage.reset(new MemoryStorage(file_bucket_buf, header.file_bucket_size));
m_file_entry_storage.reset(new MemoryStorage(file_entry_buf, header.file_entry_size));
} else {
m_dir_bucket_storage.reset(new SubStorage(base, header.directory_bucket_offset, header.directory_bucket_size));
m_dir_entry_storage.reset(new SubStorage(base, header.directory_entry_offset, header.directory_entry_size));
m_file_bucket_storage.reset(new SubStorage(base, header.file_bucket_offset, header.file_bucket_size));
m_file_entry_storage.reset(new SubStorage(base, header.file_entry_offset, header.file_entry_size));
}
/* Ensure we allocated storages successfully. */
R_UNLESS(m_dir_bucket_storage != nullptr, fs::ResultAllocationMemoryFailedInRomFsFileSystemA());
R_UNLESS(m_dir_entry_storage != nullptr, fs::ResultAllocationMemoryFailedInRomFsFileSystemA());
R_UNLESS(m_file_bucket_storage != nullptr, fs::ResultAllocationMemoryFailedInRomFsFileSystemA());
R_UNLESS(m_file_entry_storage != nullptr, fs::ResultAllocationMemoryFailedInRomFsFileSystemA());
/* Initialize the rom table. */
{
SubStorage db(m_dir_bucket_storage.get(), 0, header.directory_bucket_size);
SubStorage de(m_dir_entry_storage.get(), 0, header.directory_entry_size);
SubStorage fb(m_file_bucket_storage.get(), 0, header.file_bucket_size);
SubStorage fe(m_file_entry_storage.get(), 0, header.file_entry_size);
R_TRY(m_rom_file_table.Initialize(db, de, fb, fe));
}
/* Set members. */
m_entry_size = header.body_offset;
m_base_storage = base;
R_SUCCEED();
}
Result RomFsFileSystem::Initialize(std::unique_ptr<IStorage>&& base, void *work, size_t work_size, bool use_cache) {
m_unique_storage = std::move(base);
R_RETURN(this->Initialize(m_unique_storage.get(), work, work_size, use_cache));
}
Result RomFsFileSystem::GetFileInfo(RomFileTable::FileInfo *out, const char *path) {
R_TRY_CATCH(m_rom_file_table.OpenFile(out, path)) {
R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound());
R_CONVERT(fs::ResultDbmInvalidOperation, fs::ResultPathNotFound());
} R_END_TRY_CATCH;
R_SUCCEED();
}
IStorage *RomFsFileSystem::GetBaseStorage() {
return m_base_storage;
}
RomFsFileSystem::RomFileTable *RomFsFileSystem::GetRomFileTable() {
return std::addressof(m_rom_file_table);
}
Result RomFsFileSystem::GetFileBaseOffset(s64 *out, const char *path) {
AMS_ABORT_UNLESS(out != nullptr);
AMS_ABORT_UNLESS(path != nullptr);
RomFileTable::FileInfo info;
R_TRY(this->GetFileInfo(std::addressof(info), path));
*out = m_entry_size + info.offset.Get();
R_SUCCEED();
}
Result RomFsFileSystem::DoCreateFile(const fs::Path &path, s64 size, int flags) {
AMS_UNUSED(path, size, flags);
R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem());
}
Result RomFsFileSystem::DoDeleteFile(const fs::Path &path) {
AMS_UNUSED(path);
R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem());
}
Result RomFsFileSystem::DoCreateDirectory(const fs::Path &path) {
AMS_UNUSED(path);
R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem());
}
Result RomFsFileSystem::DoDeleteDirectory(const fs::Path &path) {
AMS_UNUSED(path);
R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem());
}
Result RomFsFileSystem::DoDeleteDirectoryRecursively(const fs::Path &path) {
AMS_UNUSED(path);
R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem());
}
Result RomFsFileSystem::DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) {
AMS_UNUSED(old_path, new_path);
R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem());
}
Result RomFsFileSystem::DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) {
AMS_UNUSED(old_path, new_path);
R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem());
}
Result RomFsFileSystem::DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) {
HierarchicalRomFileTable::FindPosition find_pos;
R_TRY_CATCH(m_rom_file_table.FindOpen(std::addressof(find_pos), path.GetString())) {
R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound())
R_CATCH(fs::ResultDbmInvalidOperation) {
*out = fs::DirectoryEntryType_File;
R_SUCCEED();
}
} R_END_TRY_CATCH;
*out = fs::DirectoryEntryType_Directory;
R_SUCCEED();
}
Result RomFsFileSystem::DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) {
AMS_ASSERT(out_file != nullptr);
R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidOpenMode());
RomFileTable::FileInfo file_info{};
R_TRY(this->GetFileInfo(std::addressof(file_info), path.GetString()));
auto file = std::make_unique<RomFsFile>(this, m_entry_size + file_info.offset.Get(), m_entry_size + file_info.offset.Get() + file_info.size.Get());
R_UNLESS(file != nullptr, fs::ResultAllocationMemoryFailedInRomFsFileSystemB());
*out_file = std::move(file);
R_SUCCEED();
}
Result RomFsFileSystem::DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) {
AMS_ASSERT(out_dir != nullptr);
RomFileTable::FindPosition find;
R_TRY_CATCH(m_rom_file_table.FindOpen(std::addressof(find), path.GetString())) {
R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound())
R_CONVERT(fs::ResultDbmInvalidOperation, fs::ResultPathNotFound())
} R_END_TRY_CATCH;
auto dir = std::make_unique<RomFsDirectory>(this, find, mode);
R_UNLESS(dir != nullptr, fs::ResultAllocationMemoryFailedInRomFsFileSystemC());
*out_dir = std::move(dir);
R_SUCCEED();
}
Result RomFsFileSystem::DoCommit() {
R_SUCCEED();
}
Result RomFsFileSystem::DoGetFreeSpaceSize(s64 *out, const fs::Path &path) {
AMS_UNUSED(path);
*out = 0;
R_SUCCEED();
}
Result RomFsFileSystem::DoGetTotalSpaceSize(s64 *out, const fs::Path &path) {
AMS_UNUSED(out, path);
R_THROW(fs::ResultUnsupportedGetTotalSpaceSizeForRomFsFileSystem());
}
Result RomFsFileSystem::DoCleanDirectoryRecursively(const fs::Path &path) {
AMS_UNUSED(path);
R_THROW(fs::ResultUnsupportedWriteForRomFsFileSystem());
}
Result RomFsFileSystem::DoCommitProvisionally(s64 counter) {
AMS_UNUSED(counter);
R_THROW(fs::ResultUnsupportedCommitProvisionallyForRomFsFileSystem());
}
Result RomFsFileSystem::DoRollback() {
R_SUCCEED();
}
}

View File

@@ -1,171 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
namespace ams::fs {
namespace impl {
Result ReadSaveDataFileSystemExtraData(SaveDataExtraData *out, SaveDataId id) {
auto fsp = impl::GetFileSystemProxyServiceObject();
AMS_FS_R_TRY(fsp->ReadSaveDataFileSystemExtraData(sf::OutBuffer(out, sizeof(*out)), id));
R_SUCCEED();
}
Result ReadSaveDataFileSystemExtraData(SaveDataExtraData *out, SaveDataSpaceId space_id, SaveDataId id) {
auto fsp = impl::GetFileSystemProxyServiceObject();
AMS_FS_R_TRY(fsp->ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(sf::OutBuffer(out, sizeof(*out)), static_cast<u8>(space_id), id));
R_SUCCEED();
}
Result WriteSaveDataFileSystemExtraData(SaveDataSpaceId space_id, SaveDataId id, const SaveDataExtraData &extra_data) {
auto fsp = impl::GetFileSystemProxyServiceObject();
AMS_FS_R_TRY(fsp->WriteSaveDataFileSystemExtraData(id, static_cast<u8>(space_id), sf::InBuffer(std::addressof(extra_data), sizeof(extra_data))));
R_SUCCEED();
}
}
void DisableAutoSaveDataCreation() {
auto fsp = impl::GetFileSystemProxyServiceObject();
AMS_FS_R_ABORT_UNLESS(fsp->DisableAutoSaveDataCreation());
}
Result CreateSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId save_id, UserId user_id, u64 owner_id, s64 size, s64 journal_size, u32 flags) {
auto create_impl = [=]() -> Result {
const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::System, user_id, save_id);
const SaveDataCreationInfo info = {
.size = size,
.journal_size = journal_size,
.block_size = DefaultSaveDataBlockSize,
.owner_id = owner_id,
.flags = flags,
.space_id = space_id,
.pseudo = false,
};
auto fsp = impl::GetFileSystemProxyServiceObject();
R_RETURN(fsp->CreateSaveDataFileSystemBySystemSaveDataId(attribute, info));
};
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(create_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_CREATE_SYSTEM_SAVE_DATA(space_id, save_id, user_id, owner_id, size, journal_size, flags)));
R_SUCCEED();
}
Result CreateSystemSaveData(SystemSaveDataId save_id, s64 size, s64 journal_size, u32 flags) {
R_RETURN(CreateSystemSaveData(SaveDataSpaceId::System, save_id, InvalidUserId, 0, size, journal_size, flags));
}
Result CreateSystemSaveData(SystemSaveDataId save_id, u64 owner_id, s64 size, s64 journal_size, u32 flags) {
R_RETURN(CreateSystemSaveData(SaveDataSpaceId::System, save_id, InvalidUserId, owner_id, size, journal_size, flags));
}
Result CreateSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId save_id, u64 owner_id, s64 size, s64 journal_size, u32 flags) {
R_RETURN(CreateSystemSaveData(space_id, save_id, InvalidUserId, owner_id, size, journal_size, flags));
}
Result CreateSystemSaveData(SystemSaveDataId save_id, UserId user_id, s64 size, s64 journal_size, u32 flags) {
R_RETURN(CreateSystemSaveData(SaveDataSpaceId::System, save_id, user_id, 0, size, journal_size, flags));
}
Result CreateSystemSaveData(SystemSaveDataId save_id, UserId user_id, u64 owner_id, s64 size, s64 journal_size, u32 flags) {
R_RETURN(CreateSystemSaveData(SaveDataSpaceId::System, save_id, user_id, owner_id, size, journal_size, flags));
}
Result DeleteSaveData(SaveDataId id) {
auto delete_impl = [=]() -> Result {
auto fsp = impl::GetFileSystemProxyServiceObject();
R_RETURN(fsp->DeleteSaveDataFileSystem(id));
};
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(delete_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID, id));
R_SUCCEED();
}
Result DeleteSaveData(SaveDataSpaceId space_id, SaveDataId id) {
auto delete_impl = [=]() -> Result {
auto fsp = impl::GetFileSystemProxyServiceObject();
R_RETURN(fsp->DeleteSaveDataFileSystemBySaveDataSpaceId(static_cast<u8>(space_id), id));
};
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(delete_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_DELETE_SAVE_DATA(space_id, id)));
R_SUCCEED();
}
Result DeleteSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId id, UserId user_id) {
auto delete_impl = [=]() -> Result {
const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::System, user_id, id);
auto fsp = impl::GetFileSystemProxyServiceObject();
R_RETURN(fsp->DeleteSaveDataFileSystemBySaveDataAttribute(static_cast<u8>(space_id), attribute));
};
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(delete_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_DELETE_SYSTEM_SAVE_DATA(space_id, id, user_id)));
R_SUCCEED();
}
Result GetSaveDataFlags(u32 *out, SaveDataId id) {
SaveDataExtraData extra_data;
R_TRY(impl::ReadSaveDataFileSystemExtraData(std::addressof(extra_data), id));
*out = extra_data.flags;
R_SUCCEED();
}
Result GetSaveDataFlags(u32 *out, SaveDataSpaceId space_id, SaveDataId id) {
SaveDataExtraData extra_data;
R_TRY(impl::ReadSaveDataFileSystemExtraData(std::addressof(extra_data), space_id, id));
*out = extra_data.flags;
R_SUCCEED();
}
Result SetSaveDataFlags(SaveDataId id, SaveDataSpaceId space_id, u32 flags) {
SaveDataExtraData extra_data;
R_TRY(impl::ReadSaveDataFileSystemExtraData(std::addressof(extra_data), space_id, id));
extra_data.flags = flags;
R_RETURN(impl::WriteSaveDataFileSystemExtraData(space_id, id, extra_data));
}
Result GetSaveDataAvailableSize(s64 *out, SaveDataId id) {
SaveDataExtraData extra_data;
R_TRY(impl::ReadSaveDataFileSystemExtraData(std::addressof(extra_data), id));
*out = extra_data.available_size;
R_SUCCEED();
}
Result GetSaveDataJournalSize(s64 *out, SaveDataId id) {
SaveDataExtraData extra_data;
R_TRY(impl::ReadSaveDataFileSystemExtraData(std::addressof(extra_data), id));
*out = extra_data.journal_size;
R_SUCCEED();
}
Result ExtendSaveData(SaveDataSpaceId space_id, SaveDataId id, s64 available_size, s64 journal_size) {
auto extend_impl = [=]() -> Result {
auto fsp = impl::GetFileSystemProxyServiceObject();
R_RETURN(fsp->ExtendSaveDataFileSystem(static_cast<u8>(space_id), id, available_size, journal_size));
};
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(extend_impl(), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_EXTEND_SAVE_DATA(space_id, id, available_size, journal_size)));
R_SUCCEED();
}
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright (c) 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::fs {
template<typename T>
class ScopedSetter {
NON_COPYABLE(ScopedSetter);
private:
T *m_ptr;
T m_value;
public:
constexpr ALWAYS_INLINE ScopedSetter(T &p, T v) : m_ptr(std::addressof(p)), m_value(v) { /* ... */ }
ALWAYS_INLINE ~ScopedSetter() {
if (m_ptr) {
*m_ptr = m_value;
}
}
ALWAYS_INLINE ScopedSetter(ScopedSetter &&rhs) {
m_ptr = rhs.m_ptr;
m_value = rhs.m_value;
rhs.Reset();
}
ALWAYS_INLINE ScopedSetter &operator=(ScopedSetter &&rhs) {
m_ptr = rhs.m_ptr;
m_value = rhs.m_value;
rhs.Reset();
return *this;
}
ALWAYS_INLINE void Set(T v) { m_value = v; }
private:
ALWAYS_INLINE void Reset() {
m_ptr = nullptr;
}
};
template<typename T>
ALWAYS_INLINE ScopedSetter<T> MakeScopedSetter(T &p, T v) {
return ScopedSetter<T>(p, v);
}
}

View File

@@ -1,213 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
#include "impl/fs_file_system_service_object_adapter.hpp"
#include "impl/fs_event_notifier_service_object_adapter.hpp"
namespace ams::fs {
namespace {
constexpr inline const char AtmosphereErrorReportDirectory[] = "/atmosphere/erpt_reports";
/* NOTE: Nintendo does not attach a generator to a mounted SD card filesystem. */
/* However, it is desirable for homebrew to be able to access SD via common path. */
class SdCardCommonMountNameGenerator : public fsa::ICommonMountNameGenerator, public impl::Newable {
public:
explicit SdCardCommonMountNameGenerator() { /* ... */ }
virtual Result GenerateCommonMountName(char *dst, size_t dst_size) override {
/* Determine how much space we need. */
const size_t needed_size = util::Strnlen(impl::SdCardFileSystemMountName, MountNameLengthMax) + 2;
AMS_ABORT_UNLESS(dst_size >= needed_size);
/* Generate the name. */
const auto size = util::SNPrintf(dst, dst_size, "%s:", impl::SdCardFileSystemMountName);
AMS_ASSERT(static_cast<size_t>(size) == needed_size - 1);
AMS_UNUSED(size);
R_SUCCEED();
}
};
}
Result MountSdCard(const char *name) {
/* Validate the mount name. */
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(impl::CheckMountNameAllowingReserved(name), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, name));
/* Open the SD card filesystem. */
auto fsp = impl::GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
R_TRY(fsp->OpenSdCardFileSystem(std::addressof(fs)));
/* Allocate a new filesystem wrapper. */
auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs));
R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInSdCardA());
/* Allocate a new mountname generator. */
/* NOTE: Nintendo does not attach a generator. */
auto generator = std::make_unique<SdCardCommonMountNameGenerator>();
R_UNLESS(generator != nullptr, fs::ResultAllocationMemoryFailedInSdCardA());
/* Register. */
R_RETURN(fsa::Register(name, std::move(fsa), std::move(generator)));
}
Result MountSdCardErrorReportDirectoryForAtmosphere(const char *name) {
/* Validate the mount name. */
R_TRY(impl::CheckMountName(name));
/* Open the SD card filesystem. */
auto fsp = impl::GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
R_TRY(fsp->OpenSdCardFileSystem(std::addressof(fs)));
/* Allocate a new filesystem wrapper. */
auto fsa = fs::AllocateShared<impl::FileSystemServiceObjectAdapter>(std::move(fs));
R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInSdCardA());
/* Ensure that the error report directory exists. */
constexpr fs::Path fs_path = fs::MakeConstantPath(AtmosphereErrorReportDirectory);
R_TRY(fssystem::EnsureDirectory(fsa.get(), fs_path));
/* Create a subdirectory filesystem. */
auto subdir_fs = std::make_unique<fssystem::SubDirectoryFileSystem>(std::move(fsa));
R_UNLESS(subdir_fs != nullptr, fs::ResultAllocationMemoryFailedInSdCardA());
R_TRY(subdir_fs->Initialize(fs_path));
/* Register. */
R_RETURN(fsa::Register(name, std::move(subdir_fs)));
}
Result OpenSdCardDetectionEventNotifier(std::unique_ptr<IEventNotifier> *out) {
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Try to open an event notifier. */
sf::SharedPointer<fssrv::sf::IEventNotifier> notifier;
AMS_FS_R_TRY(fsp->OpenSdCardDetectionEventNotifier(std::addressof(notifier)));
/* Create an event notifier adapter. */
auto adapter = std::make_unique<impl::EventNotifierObjectAdapter>(std::move(notifier));
AMS_FS_R_UNLESS(adapter != nullptr, fs::ResultAllocationMemoryFailedInSdCardB());
*out = std::move(adapter);
R_SUCCEED();
}
bool IsSdCardInserted() {
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_ABORT_UNLESS(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get insertion status. */
bool inserted;
AMS_FS_R_ABORT_UNLESS(device_operator->IsSdCardInserted(std::addressof(inserted)));
return inserted;
}
Result GetSdCardSpeedMode(SdCardSpeedMode *out) {
/* Check pre-conditions. */
AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get the speed mode. */
s64 speed_mode = 0;
AMS_FS_R_TRY(device_operator->GetSdCardSpeedMode(std::addressof(speed_mode)));
*out = static_cast<SdCardSpeedMode>(speed_mode);
R_SUCCEED();
}
Result GetSdCardCid(void *dst, size_t size) {
/* Check pre-conditions. */
AMS_FS_R_UNLESS(dst != nullptr, fs::ResultNullptrArgument());
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get the cid. */
AMS_FS_R_TRY(device_operator->GetSdCardCid(sf::OutBuffer(dst, size), static_cast<s64>(size)));
R_SUCCEED();
}
Result GetSdCardUserAreaSize(s64 *out) {
/* Check pre-conditions. */
AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get the size. */
AMS_FS_R_TRY(device_operator->GetSdCardUserAreaSize(out));
R_SUCCEED();
}
Result GetSdCardProtectedAreaSize(s64 *out) {
/* Check pre-conditions. */
AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get the size. */
AMS_FS_R_TRY(device_operator->GetSdCardProtectedAreaSize(out));
R_SUCCEED();
}
Result GetAndClearSdCardErrorInfo(StorageErrorInfo *out_sei, size_t *out_log_size, char *out_log_buffer, size_t log_buffer_size) {
/* Check pre-conditions. */
AMS_FS_R_UNLESS(out_sei != nullptr, fs::ResultNullptrArgument());
AMS_FS_R_UNLESS(out_log_size != nullptr, fs::ResultNullptrArgument());
AMS_FS_R_UNLESS(out_log_buffer != nullptr, fs::ResultNullptrArgument());
auto fsp = impl::GetFileSystemProxyServiceObject();
/* Open a device operator. */
sf::SharedPointer<fssrv::sf::IDeviceOperator> device_operator;
AMS_FS_R_TRY(fsp->OpenDeviceOperator(std::addressof(device_operator)));
/* Get the error info. */
s64 log_size = 0;
AMS_FS_R_TRY(device_operator->GetAndClearSdCardErrorInfo(out_sei, std::addressof(log_size), sf::OutBuffer(out_log_buffer, log_buffer_size), static_cast<s64>(log_buffer_size)));
*out_log_size = static_cast<size_t>(log_size);
R_SUCCEED();
}
}

View File

@@ -1,58 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_filesystem_accessor.hpp"
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
namespace ams::fs {
namespace {
Result GetSignedSystemPartitionOnSdCardValid(char *out, impl::FileSystemAccessor *accessor) {
R_TRY_CATCH(accessor->QueryEntry(out, sizeof(*out), nullptr, 0, fsa::QueryId::IsSignedSystemPartitionOnSdCardValid, "/")) {
/* If querying isn't supported, then the partition isn't valid. */
R_CATCH(fs::ResultUnsupportedOperation) { *out = false; }
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
R_SUCCEED();
}
}
bool IsSignedSystemPartitionOnSdCardValid(const char *system_root_path) {
/* Get the accessor for the system filesystem. */
impl::FileSystemAccessor *accessor;
const char *sub_path;
AMS_FS_R_ABORT_UNLESS(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), system_root_path));
char is_valid;
AMS_FS_R_ABORT_UNLESS(GetSignedSystemPartitionOnSdCardValid(std::addressof(is_valid), accessor));
return is_valid;
}
bool IsSignedSystemPartitionOnSdCardValidDeprecated() {
/* Ensure we only call with correct version. */
auto version = hos::GetVersion();
AMS_ABORT_UNLESS(hos::Version_4_0_0 <= version && version < hos::Version_8_0_0);
/* Check that the partition is valid. */
auto fsp = impl::GetFileSystemProxyServiceObject();
bool is_valid;
AMS_FS_R_ABORT_UNLESS(fsp->IsSignedSystemPartitionOnSdCardValid(std::addressof(is_valid)));
return is_valid;
}
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
namespace ams::fs {
Result QueryMountSystemDataCacheSize(size_t *out, ncm::SystemDataId data_id) {
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM(impl::QueryMountDataCacheSize(out, data_id, ncm::StorageId::BuiltInSystem), nullptr, AMS_FS_IMPL_ACCESS_LOG_FORMAT_QUERY_MOUNT_SYSTEM_DATA_CACHE_SIZE(data_id, out)));
R_SUCCEED();
}
Result MountSystemData(const char *name, ncm::SystemDataId data_id) {
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(impl::MountData(name, data_id, ncm::StorageId::BuiltInSystem), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_DATA(name, data_id)));
AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
Result MountSystemData(const char *name, ncm::SystemDataId data_id, void *cache_buffer, size_t cache_size) {
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(impl::MountData(name, data_id, ncm::StorageId::BuiltInSystem, cache_buffer, cache_size), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_DATA(name, data_id)));
AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fsa/fs_mount_utils.hpp"
#include "impl/fs_file_system_proxy_service_object.hpp"
#include "impl/fs_file_system_service_object_adapter.hpp"
namespace ams::fs {
Result MountSystemSaveData(const char *name, SystemSaveDataId id) {
R_RETURN(MountSystemSaveData(name, id, InvalidUserId));
}
Result MountSystemSaveData(const char *name, SaveDataSpaceId space_id, SystemSaveDataId id) {
R_RETURN(MountSystemSaveData(name, space_id, id, InvalidUserId));
}
Result MountSystemSaveData(const char *name, SystemSaveDataId id, UserId user_id) {
R_RETURN(MountSystemSaveData(name, SaveDataSpaceId::System, id, user_id));
}
Result MountSystemSaveData(const char *name, SaveDataSpaceId space_id, SystemSaveDataId id, UserId user_id) {
auto mount_impl = [=]() -> Result {
/* Validate the mount name. */
R_TRY(impl::CheckMountName(name));
/* Create the attribute. */
const auto attribute = SaveDataAttribute::Make(ncm::InvalidProgramId, SaveDataType::System, user_id, id);
/* Open the filesystem. */
auto fsp = impl::GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
R_TRY(fsp->OpenSaveDataFileSystemBySystemSaveDataId(std::addressof(fs), static_cast<u8>(space_id), attribute));
/* Allocate a new filesystem wrapper. */
auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs));
R_UNLESS(fsa != nullptr, fs::ResultAllocationMemoryFailedInSystemSaveDataA());
/* Register. */
R_RETURN(fsa::Register(name, std::move(fsa)));
};
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(mount_impl(), name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_SAVE_DATA(name, space_id, id, user_id)));
AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(name);
R_SUCCEED();
}
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fs_directory_accessor.hpp"
#include "fs_filesystem_accessor.hpp"
namespace ams::fs::impl {
DirectoryAccessor::DirectoryAccessor(std::unique_ptr<fsa::IDirectory>&& d, FileSystemAccessor &p) : m_impl(std::move(d)), m_parent(p) {
/* ... */
}
DirectoryAccessor::~DirectoryAccessor() {
m_impl.reset();
m_parent.NotifyCloseDirectory(this);
}
Result DirectoryAccessor::Read(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) {
R_RETURN(m_impl->Read(out_count, out_entries, max_entries));
}
Result DirectoryAccessor::GetEntryCount(s64 *out) {
R_RETURN(m_impl->GetEntryCount(out));
}
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright (c) 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::fs::impl {
class FileSystemAccessor;
class DirectoryAccessor : public util::IntrusiveListBaseNode<DirectoryAccessor>, public Newable {
NON_COPYABLE(DirectoryAccessor);
private:
std::unique_ptr<fsa::IDirectory> m_impl;
FileSystemAccessor &m_parent;
public:
DirectoryAccessor(std::unique_ptr<fsa::IDirectory>&& d, FileSystemAccessor &p);
~DirectoryAccessor();
Result Read(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries);
Result GetEntryCount(s64 *out);
FileSystemAccessor *GetParent() const { return std::addressof(m_parent); }
};
}

View File

@@ -1,127 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "../fs_scoped_setter.hpp"
#include "../fs_file_path_hash.hpp"
#include "fs_file_accessor.hpp"
#include "fs_filesystem_accessor.hpp"
namespace ams::fs::impl {
FileAccessor::FileAccessor(std::unique_ptr<fsa::IFile>&& f, FileSystemAccessor *p, OpenMode mode)
: m_impl(std::move(f)), m_parent(p), m_write_state(WriteState::None), m_write_result(ResultSuccess()), m_open_mode(mode)
{
/* ... */
}
FileAccessor::~FileAccessor() {
/* Ensure that all files are flushed. */
if (R_SUCCEEDED(m_write_result)) {
AMS_FS_ABORT_UNLESS_WITH_RESULT(m_write_state != WriteState::NeedsFlush, fs::ResultNeedFlush());
}
m_impl.reset();
if (m_parent != nullptr) {
m_parent->NotifyCloseFile(this);
}
}
Result FileAccessor::ReadWithCacheAccessLog(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option, bool use_path_cache, bool use_data_cache) {
/* TODO */
AMS_UNUSED(out, offset, buf, size, option, use_path_cache, use_data_cache);
AMS_ABORT();
}
Result FileAccessor::ReadWithoutCacheAccessLog(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option) {
R_RETURN(m_impl->Read(out, offset, buf, size, option));
}
Result FileAccessor::Read(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option) {
/* Get a handle to this file for use in logging. */
FileHandle handle = { this };
/* Fail after a write fails. */
R_UNLESS(R_SUCCEEDED(m_write_result), AMS_FS_IMPL_ACCESS_LOG_WITH_NAME(m_write_result, handle, "ReadFile", AMS_FS_IMPL_ACCESS_LOG_FORMAT_READ_FILE(out, offset, size)));
/* TODO: Support cache. */
const bool use_path_cache = m_parent != nullptr && m_file_path_hash != nullptr;
const bool use_data_cache = /* TODO */false && m_parent != nullptr && m_parent->IsFileDataCacheAttachable();
if (use_path_cache && use_data_cache && false) {
/* TODO */
R_RETURN(this->ReadWithCacheAccessLog(out, offset, buf, size, option, use_path_cache, use_data_cache));
} else {
R_RETURN(AMS_FS_IMPL_ACCESS_LOG_WITH_NAME(this->ReadWithoutCacheAccessLog(out, offset, buf, size, option), handle, "ReadFile", AMS_FS_IMPL_ACCESS_LOG_FORMAT_READ_FILE(out, offset, size)));
}
}
Result FileAccessor::Write(s64 offset, const void *buf, size_t size, const WriteOption &option) {
/* Fail after a write fails. */
R_TRY(m_write_result);
auto setter = MakeScopedSetter(m_write_state, WriteState::Failed);
if (m_file_path_hash != nullptr && /* TODO */ false) {
/* TODO */
AMS_ABORT();
} else {
R_TRY(this->UpdateLastResult(m_impl->Write(offset, buf, size, option)));
}
setter.Set(option.HasFlushFlag() ? WriteState::None : WriteState::NeedsFlush);
R_SUCCEED();
}
Result FileAccessor::Flush() {
/* Fail after a write fails. */
R_TRY(m_write_result);
auto setter = MakeScopedSetter(m_write_state, WriteState::Failed);
R_TRY(this->UpdateLastResult(m_impl->Flush()));
setter.Set(WriteState::None);
R_SUCCEED();
}
Result FileAccessor::SetSize(s64 size) {
/* Fail after a write fails. */
R_TRY(m_write_result);
const WriteState old_write_state = m_write_state;
auto setter = MakeScopedSetter(m_write_state, WriteState::Failed);
R_TRY(this->UpdateLastResult(m_impl->SetSize(size)));
if (m_file_path_hash != nullptr) {
/* TODO: invalidate path cache */
}
setter.Set(old_write_state);
R_SUCCEED();
}
Result FileAccessor::GetSize(s64 *out) {
/* Fail after a write fails. */
R_TRY(m_write_result);
R_RETURN(m_impl->GetSize(out));
}
Result FileAccessor::OperateRange(void *dst, size_t dst_size, OperationId operation, s64 offset, s64 size, const void *src, size_t src_size) {
R_RETURN(m_impl->OperateRange(dst, dst_size, operation, offset, size, src, src_size));
}
}

View File

@@ -1,68 +0,0 @@
/*
* Copyright (c) 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::fs::impl {
struct FilePathHash;
class FileSystemAccessor;
enum class WriteState {
None,
NeedsFlush,
Failed,
};
class FileAccessor : public util::IntrusiveListBaseNode<FileAccessor>, public Newable {
NON_COPYABLE(FileAccessor);
private:
std::unique_ptr<fsa::IFile> m_impl;
FileSystemAccessor * const m_parent;
WriteState m_write_state;
Result m_write_result;
const OpenMode m_open_mode;
std::unique_ptr<FilePathHash> m_file_path_hash;
s32 m_path_hash_index;
public:
FileAccessor(std::unique_ptr<fsa::IFile>&& f, FileSystemAccessor *p, OpenMode mode);
~FileAccessor();
Result Read(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option);
Result Write(s64 offset, const void *buf, size_t size, const WriteOption &option);
Result Flush();
Result SetSize(s64 size);
Result GetSize(s64 *out);
Result OperateRange(void *dst, size_t dst_size, OperationId operation, s64 offset, s64 size, const void *src, size_t src_size);
OpenMode GetOpenMode() const { return m_open_mode; }
WriteState GetWriteState() const { return m_write_state; }
FileSystemAccessor *GetParent() const { return m_parent; }
void SetFilePathHash(std::unique_ptr<FilePathHash>&& file_path_hash, s32 index);
Result ReadWithoutCacheAccessLog(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option);
private:
Result ReadWithCacheAccessLog(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option, bool use_path_cache, bool use_data_cache);
ALWAYS_INLINE Result UpdateLastResult(Result r) {
if (!fs::ResultNotEnoughFreeSpace::Includes(r)) {
m_write_result = r;
}
R_RETURN(r);
}
};
}

View File

@@ -1,314 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fs_file_accessor.hpp"
#include "fs_directory_accessor.hpp"
#include "fs_filesystem_accessor.hpp"
namespace ams::fs::impl {
namespace {
template<typename List, typename Iter>
void Remove(List &list, Iter *desired) {
for (auto it = list.cbegin(); it != list.cend(); ++it) {
if (it.operator->() == desired) {
list.erase(it);
return;
}
}
/* This should never happen. */
AMS_ABORT();
}
Result SetMountName(char *dst, const char *name) {
R_UNLESS(name[0] != 0, fs::ResultInvalidMountName());
const size_t n_len = util::Strlcpy<char>(dst, name, MountNameLengthMax + 1);
R_UNLESS(n_len <= MountNameLengthMax, fs::ResultInvalidMountName());
R_SUCCEED();
}
template<typename List>
Result ValidateNoOpenWriteModeFiles(List &list) {
for (auto it = list.cbegin(); it != list.cend(); it++) {
R_UNLESS((it->GetOpenMode() & OpenMode_Write) == 0, fs::ResultWriteModeFileNotClosed());
}
R_SUCCEED();
}
}
FileSystemAccessor::FileSystemAccessor(const char *n, std::unique_ptr<fsa::IFileSystem> &&fs, std::unique_ptr<fsa::ICommonMountNameGenerator> &&generator)
: m_impl(std::move(fs)), m_open_list_lock(), m_mount_name_generator(std::move(generator)),
m_access_log_enabled(false), m_data_cache_attachable(false), m_path_cache_attachable(false), m_path_cache_attached(false), m_multi_commit_supported(false),
m_path_flags()
{
R_ABORT_UNLESS(SetMountName(m_name.str, n));
if (std::strcmp(m_name.str, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME) == 0) {
m_path_flags.AllowWindowsPath();
}
}
FileSystemAccessor::~FileSystemAccessor() {
std::scoped_lock lk(m_open_list_lock);
/* TODO: Iterate over list entries. */
if (!m_open_file_list.empty()) { R_ABORT_UNLESS(fs::ResultFileNotClosed()); }
if (!m_open_dir_list.empty()) { R_ABORT_UNLESS(fs::ResultDirectoryNotClosed()); }
if (m_path_cache_attached) {
/* TODO: Invalidate path cache */
}
}
Result FileSystemAccessor::GetCommonMountName(char *dst, size_t dst_size) const {
R_UNLESS(m_mount_name_generator != nullptr, fs::ResultPreconditionViolation());
R_RETURN(m_mount_name_generator->GenerateCommonMountName(dst, dst_size));
}
std::shared_ptr<fssrv::impl::FileSystemInterfaceAdapter> FileSystemAccessor::GetMultiCommitTarget() {
if (m_multi_commit_supported) {
AMS_ABORT("TODO: Support multi commit");
}
return nullptr;
}
void FileSystemAccessor::NotifyCloseFile(FileAccessor *f) {
std::scoped_lock lk(m_open_list_lock);
Remove(m_open_file_list, f);
}
void FileSystemAccessor::NotifyCloseDirectory(DirectoryAccessor *d) {
std::scoped_lock lk(m_open_list_lock);
Remove(m_open_dir_list, d);
}
Result FileSystemAccessor::SetUpPath(fs::Path *out, const char *p) {
/* Initialize the path appropriately. */
bool normalized;
size_t len;
if (R_SUCCEEDED(PathFormatter::IsNormalized(std::addressof(normalized), std::addressof(len), p, m_path_flags)) && normalized) {
/* We can use the input buffer directly. */
out->SetShallowBuffer(p);
} else {
/* Initialize with appropriate slash replacement. */
if (m_path_flags.IsWindowsPathAllowed()) {
R_TRY(out->InitializeWithReplaceForwardSlashes(p));
} else {
R_TRY(out->InitializeWithReplaceBackslash(p));
}
/* Ensure we're normalized. */
R_TRY(out->Normalize(m_path_flags));
}
/* Check the path isn't too long. */
R_UNLESS(out->GetLength() <= fs::EntryNameLengthMax, fs::ResultTooLongPath());
R_SUCCEED();
}
Result FileSystemAccessor::CreateFile(const char *path, s64 size, int option) {
/* Create path. */
fs::Path normalized_path;
R_TRY(this->SetUpPath(std::addressof(normalized_path), path));
if (m_path_cache_attached) {
/* TODO: Path cache */
R_TRY(m_impl->CreateFile(normalized_path, size, option));
} else {
R_TRY(m_impl->CreateFile(normalized_path, size, option));
}
R_SUCCEED();
}
Result FileSystemAccessor::DeleteFile(const char *path) {
/* Create path. */
fs::Path normalized_path;
R_TRY(this->SetUpPath(std::addressof(normalized_path), path));
R_RETURN(m_impl->DeleteFile(normalized_path));
}
Result FileSystemAccessor::CreateDirectory(const char *path) {
/* Create path. */
fs::Path normalized_path;
R_TRY(this->SetUpPath(std::addressof(normalized_path), path));
R_RETURN(m_impl->CreateDirectory(normalized_path));
}
Result FileSystemAccessor::DeleteDirectory(const char *path) {
/* Create path. */
fs::Path normalized_path;
R_TRY(this->SetUpPath(std::addressof(normalized_path), path));
R_RETURN(m_impl->DeleteDirectory(normalized_path));
}
Result FileSystemAccessor::DeleteDirectoryRecursively(const char *path) {
/* Create path. */
fs::Path normalized_path;
R_TRY(this->SetUpPath(std::addressof(normalized_path), path));
R_RETURN(m_impl->DeleteDirectoryRecursively(normalized_path));
}
Result FileSystemAccessor::RenameFile(const char *old_path, const char *new_path) {
/* Create path. */
fs::Path normalized_old_path;
fs::Path normalized_new_path;
R_TRY(this->SetUpPath(std::addressof(normalized_old_path), old_path));
R_TRY(this->SetUpPath(std::addressof(normalized_new_path), new_path));
if (m_path_cache_attached) {
/* TODO: Path cache */
R_TRY(m_impl->RenameFile(normalized_old_path, normalized_new_path));
} else {
R_TRY(m_impl->RenameFile(normalized_old_path, normalized_new_path));
}
R_SUCCEED();
}
Result FileSystemAccessor::RenameDirectory(const char *old_path, const char *new_path) {
/* Create path. */
fs::Path normalized_old_path;
fs::Path normalized_new_path;
R_TRY(this->SetUpPath(std::addressof(normalized_old_path), old_path));
R_TRY(this->SetUpPath(std::addressof(normalized_new_path), new_path));
if (m_path_cache_attached) {
/* TODO: Path cache */
R_TRY(m_impl->RenameDirectory(normalized_old_path, normalized_new_path));
} else {
R_TRY(m_impl->RenameDirectory(normalized_old_path, normalized_new_path));
}
R_SUCCEED();
}
Result FileSystemAccessor::GetEntryType(DirectoryEntryType *out, const char *path) {
/* Create path. */
fs::Path normalized_path;
R_TRY(this->SetUpPath(std::addressof(normalized_path), path));
R_RETURN(m_impl->GetEntryType(out, normalized_path));
}
Result FileSystemAccessor::OpenFile(std::unique_ptr<FileAccessor> *out_file, const char *path, OpenMode mode) {
/* Create path. */
fs::Path normalized_path;
R_TRY(this->SetUpPath(std::addressof(normalized_path), path));
std::unique_ptr<fsa::IFile> file;
R_TRY(m_impl->OpenFile(std::addressof(file), normalized_path, mode));
auto accessor = new FileAccessor(std::move(file), this, mode);
R_UNLESS(accessor != nullptr, fs::ResultAllocationMemoryFailedInFileSystemAccessorA());
{
std::scoped_lock lk(m_open_list_lock);
m_open_file_list.push_back(*accessor);
}
if (m_path_cache_attached) {
if (mode & OpenMode_AllowAppend) {
/* TODO: Append Path cache */
} else {
/* TODO: Non-append path cache */
}
}
out_file->reset(accessor);
R_SUCCEED();
}
Result FileSystemAccessor::OpenDirectory(std::unique_ptr<DirectoryAccessor> *out_dir, const char *path, OpenDirectoryMode mode) {
/* Create path. */
fs::Path normalized_path;
R_TRY(this->SetUpPath(std::addressof(normalized_path), path));
std::unique_ptr<fsa::IDirectory> dir;
R_TRY(m_impl->OpenDirectory(std::addressof(dir), normalized_path, mode));
auto accessor = new DirectoryAccessor(std::move(dir), *this);
R_UNLESS(accessor != nullptr, fs::ResultAllocationMemoryFailedInFileSystemAccessorB());
{
std::scoped_lock lk(m_open_list_lock);
m_open_dir_list.push_back(*accessor);
}
out_dir->reset(accessor);
R_SUCCEED();
}
Result FileSystemAccessor::Commit() {
{
std::scoped_lock lk(m_open_list_lock);
R_ABORT_UNLESS(ValidateNoOpenWriteModeFiles(m_open_file_list));
}
R_RETURN(m_impl->Commit());
}
Result FileSystemAccessor::GetFreeSpaceSize(s64 *out, const char *path) {
/* Create path. */
fs::Path normalized_path;
R_TRY(this->SetUpPath(std::addressof(normalized_path), path));
R_RETURN(m_impl->GetFreeSpaceSize(out, normalized_path));
}
Result FileSystemAccessor::GetTotalSpaceSize(s64 *out, const char *path) {
/* Create path. */
fs::Path normalized_path;
R_TRY(this->SetUpPath(std::addressof(normalized_path), path));
R_RETURN(m_impl->GetTotalSpaceSize(out, normalized_path));
}
Result FileSystemAccessor::CleanDirectoryRecursively(const char *path) {
/* Create path. */
fs::Path normalized_path;
R_TRY(this->SetUpPath(std::addressof(normalized_path), path));
R_RETURN(m_impl->CleanDirectoryRecursively(normalized_path));
}
Result FileSystemAccessor::GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) {
/* Create path. */
fs::Path normalized_path;
R_TRY(this->SetUpPath(std::addressof(normalized_path), path));
R_RETURN(m_impl->GetFileTimeStampRaw(out, normalized_path));
}
Result FileSystemAccessor::QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path) {
/* Create path. */
fs::Path normalized_path;
R_TRY(this->SetUpPath(std::addressof(normalized_path), path));
R_RETURN(m_impl->QueryEntry(dst, dst_size, src, src_size, query, normalized_path));
}
}

View File

@@ -1,101 +0,0 @@
/*
* Copyright (c) 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>
#include <stratosphere/fssrv/fssrv_interface_adapters.hpp>
#include "fs_mount_name.hpp"
namespace ams::fs::impl {
class FileAccessor;
class DirectoryAccessor;
class FileSystemAccessor : public util::IntrusiveListBaseNode<FileSystemAccessor>, public Newable {
NON_COPYABLE(FileSystemAccessor);
friend class FileAccessor;
friend class DirectoryAccessor;
private:
using FileList = util::IntrusiveListBaseTraits<FileAccessor>::ListType;
using DirList = util::IntrusiveListBaseTraits<DirectoryAccessor>::ListType;
private:
MountName m_name;
std::unique_ptr<fsa::IFileSystem> m_impl;
FileList m_open_file_list;
DirList m_open_dir_list;
os::SdkMutex m_open_list_lock;
std::unique_ptr<fsa::ICommonMountNameGenerator> m_mount_name_generator;
bool m_access_log_enabled;
bool m_data_cache_attachable;
bool m_path_cache_attachable;
bool m_path_cache_attached;
bool m_multi_commit_supported;
PathFlags m_path_flags;
public:
FileSystemAccessor(const char *name, std::unique_ptr<fsa::IFileSystem> &&fs, std::unique_ptr<fsa::ICommonMountNameGenerator> &&generator = nullptr);
virtual ~FileSystemAccessor();
Result CreateFile(const char *path, s64 size, int option);
Result DeleteFile(const char *path);
Result CreateDirectory(const char *path);
Result DeleteDirectory(const char *path);
Result DeleteDirectoryRecursively(const char *path);
Result RenameFile(const char *old_path, const char *new_path);
Result RenameDirectory(const char *old_path, const char *new_path);
Result GetEntryType(DirectoryEntryType *out, const char *path);
Result OpenFile(std::unique_ptr<FileAccessor> *out_file, const char *path, OpenMode mode);
Result OpenDirectory(std::unique_ptr<DirectoryAccessor> *out_dir, const char *path, OpenDirectoryMode mode);
Result Commit();
Result GetFreeSpaceSize(s64 *out, const char *path);
Result GetTotalSpaceSize(s64 *out, const char *path);
Result CleanDirectoryRecursively(const char *path);
Result GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path);
Result QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path);
const char *GetName() const { return m_name.str; }
Result GetCommonMountName(char *dst, size_t dst_size) const;
void SetAccessLogEnabled(bool en) { m_access_log_enabled = en; }
void SetFileDataCacheAttachable(bool en) { m_data_cache_attachable = en; }
void SetPathBasedFileDataCacheAttachable(bool en) { m_path_cache_attachable = en; }
void SetMultiCommitSupported(bool en) { m_multi_commit_supported = en; }
bool IsEnabledAccessLog() const { return m_access_log_enabled; }
bool IsFileDataCacheAttachable() const { return m_data_cache_attachable; }
bool IsPathBasedFileDataCacheAttachable() const { return m_path_cache_attachable; }
void AttachPathBasedFileDataCache() {
if (this->IsPathBasedFileDataCacheAttachable()) {
m_path_cache_attached = true;
}
}
void DetachPathBasedFileDataCache() {
m_path_cache_attached = false;
}
std::shared_ptr<fssrv::impl::FileSystemInterfaceAdapter> GetMultiCommitTarget();
fsa::IFileSystem *GetRawFileSystemUnsafe() {
return m_impl.get();
}
private:
void NotifyCloseFile(FileAccessor *f);
void NotifyCloseDirectory(DirectoryAccessor *d);
public:
Result SetUpPath(fs::Path *out, const char *p);
};
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright (c) 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::fs {
struct MountName {
char str[MountNameLengthMax + 1];
};
static_assert(util::is_pod<MountName>::value);
}

View File

@@ -1,75 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fs_mount_table.hpp"
namespace ams::fs::impl {
namespace {
bool MatchesName(const FileSystemAccessor &accessor, const char *name) {
return std::strncmp(accessor.GetName(), name, sizeof(MountName)) == 0;
}
}
bool MountTable::CanAcceptMountName(const char *name) {
for (const auto &fs : m_fs_list) {
if (MatchesName(fs, name)) {
return false;
}
}
return true;
}
Result MountTable::Mount(std::unique_ptr<FileSystemAccessor> &&fs) {
std::scoped_lock lk(m_mutex);
R_UNLESS(this->CanAcceptMountName(fs->GetName()), fs::ResultMountNameAlreadyExists());
m_fs_list.push_back(*fs.release());
R_SUCCEED();
}
Result MountTable::Find(FileSystemAccessor **out, const char *name) {
std::scoped_lock lk(m_mutex);
for (auto &fs : m_fs_list) {
if (MatchesName(fs, name)) {
*out = std::addressof(fs);
R_SUCCEED();
}
}
R_THROW(fs::ResultNotMounted());
}
void MountTable::Unmount(const char *name) {
std::scoped_lock lk(m_mutex);
for (auto it = m_fs_list.cbegin(); it != m_fs_list.cend(); it++) {
if (MatchesName(*it, name)) {
auto p = std::addressof(*it);
m_fs_list.erase(it);
delete p;
return;
}
}
R_ABORT_UNLESS(fs::ResultNotMounted());
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright (c) 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>
#include "fs_filesystem_accessor.hpp"
namespace ams::fs::impl {
class MountTable : public Newable {
NON_COPYABLE(MountTable);
NON_MOVEABLE(MountTable);
private:
using FileSystemList = util::IntrusiveListBaseTraits<FileSystemAccessor>::ListType;
private:
FileSystemList m_fs_list;
os::SdkMutex m_mutex;
public:
constexpr MountTable() : m_fs_list(), m_mutex() { /* ... */ }
private:
bool CanAcceptMountName(const char *name);
public:
Result Mount(std::unique_ptr<FileSystemAccessor> &&fs);
Result Find(FileSystemAccessor **out, const char *name);
void Unmount(const char *name);
};
}

View File

@@ -1,172 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fs_filesystem_accessor.hpp"
#include "fs_mount_utils.hpp"
#include "fs_user_mount_table.hpp"
namespace ams::fs::impl {
namespace {
const char *FindMountNameDriveSeparator(const char *path) {
for (const char *cur = path; cur < path + MountNameLengthMax + 1 && *cur != StringTraits::NullTerminator; ++cur) {
if (*cur == StringTraits::DriveSeparator) {
return cur;
}
}
return nullptr;
}
constexpr bool IsHostRootPath(const char *path) {
#if defined(ATMOSPHERE_OS_HORIZON) || defined(ATMOSPHERE_OS_WINDOWS)
return fs::IsWindowsDrive(path) || fs::IsUncPath(path);
#elif defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS)
return fs::IsPathAbsolute(path);
#else
#error "Unknown OS for host path identification"
#endif
}
Result GetMountNameAndSubPath(MountName *out_mount_name, const char **out_sub_path, const char *path) {
/* Handle the Host-path case. */
if (IsHostRootPath(path)) {
std::strncpy(out_mount_name->str, HostRootFileSystemMountName, MountNameLengthMax);
out_mount_name->str[MountNameLengthMax] = '\x00';
*out_sub_path = path;
R_SUCCEED();
}
/* Locate the drive separator. */
const char *drive_separator = FindMountNameDriveSeparator(path);
R_UNLESS(drive_separator != nullptr, fs::ResultInvalidMountName());
/* Ensure the mount name isn't too long. */
const size_t len = drive_separator - path;
R_UNLESS(0 < len, fs::ResultInvalidMountName());
R_UNLESS(len <= MountNameLengthMax, fs::ResultInvalidMountName());
/* Ensure the result sub-path is valid. */
const char *sub_path = drive_separator + 1;
const auto starts_with_dir = (sub_path[0] == StringTraits::DirectorySeparator) || (sub_path[0] == StringTraits::AlternateDirectorySeparator);
R_UNLESS(starts_with_dir, fs::ResultInvalidPathFormat());
/* Set output. */
std::memcpy(out_mount_name->str, path, len);
out_mount_name->str[len] = StringTraits::NullTerminator;
*out_sub_path = sub_path;
R_SUCCEED();
}
}
bool IsValidMountName(const char *name) {
if (name[0] == StringTraits::NullTerminator) {
return false;
}
if ((('a' <= name[0] && name[0] <= 'z') || ('A' <= name[0] && name[0] <= 'Z')) && name[1] == StringTraits::NullTerminator) {
return false;
}
size_t len = 0;
for (const char *cur = name; *cur != StringTraits::NullTerminator; ++cur) {
if (*cur == StringTraits::DriveSeparator || *cur == StringTraits::DirectorySeparator) {
return false;
}
if ((++len) > MountNameLengthMax) {
return false;
}
}
return util::VerifyUtf8String(name, len);
}
bool IsReservedMountName(const char *name) {
return name[0] == ReservedMountNamePrefixCharacter;
}
Result CheckMountName(const char *name) {
R_TRY(CheckMountNameAllowingReserved(name));
R_UNLESS(!impl::IsReservedMountName(name), fs::ResultInvalidMountName());
R_SUCCEED();
}
Result CheckMountNameAllowingReserved(const char *name) {
R_UNLESS(name != nullptr, fs::ResultInvalidMountName());
R_UNLESS(impl::IsValidMountName(name), fs::ResultInvalidMountName());
R_SUCCEED();
}
Result FindFileSystem(FileSystemAccessor **out_accessor, const char **out_sub_path, const char *path) {
R_UNLESS(out_accessor != nullptr, fs::ResultUnexpectedInFindFileSystemA());
R_UNLESS(out_sub_path != nullptr, fs::ResultUnexpectedInFindFileSystemA());
R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
R_UNLESS(strncmp(path, HostRootFileSystemMountName, util::Strnlen(HostRootFileSystemMountName, sizeof(MountName))) != 0, fs::ResultNotMounted());
MountName mount_name;
R_TRY(GetMountNameAndSubPath(std::addressof(mount_name), out_sub_path, path));
R_RETURN(impl::Find(out_accessor, mount_name.str));
}
Result Unmount(const char *name) {
impl::FileSystemAccessor *accessor;
R_TRY(impl::Find(std::addressof(accessor), name));
if (accessor->IsFileDataCacheAttachable()) {
/* TODO: Data cache purge */
}
impl::Unregister(name);
R_SUCCEED();
}
}
namespace ams::fs {
Result ConvertToFsCommonPath(char *dst, size_t dst_size, const char *src) {
/* Ensure neither argument is nullptr. */
AMS_FS_R_UNLESS(dst != nullptr, fs::ResultNullptrArgument());
AMS_FS_R_UNLESS(src != nullptr, fs::ResultNullptrArgument());
/* Get the mount name and sub path for the path. */
MountName mount_name;
const char *sub_path;
AMS_FS_R_TRY(impl::GetMountNameAndSubPath(std::addressof(mount_name), std::addressof(sub_path), src));
impl::FileSystemAccessor *accessor;
AMS_FS_R_TRY(impl::Find(std::addressof(accessor), mount_name.str));
AMS_FS_R_TRY(accessor->GetCommonMountName(dst, dst_size));
const auto mount_name_len = util::Strnlen(dst, dst_size);
const auto common_path_len = util::SNPrintf(dst + mount_name_len, dst_size - mount_name_len, "%s", sub_path);
AMS_FS_R_UNLESS(static_cast<size_t>(common_path_len) < dst_size - mount_name_len, fs::ResultTooLongPath());
R_SUCCEED();
}
void Unmount(const char *mount_name) {
AMS_FS_R_ABORT_UNLESS(AMS_FS_IMPL_ACCESS_LOG_UNMOUNT(impl::Unmount(mount_name), mount_name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, mount_name));
}
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright (c) 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::fs::impl {
class FileSystemAccessor;
Result FindFileSystem(FileSystemAccessor **out_accessor, const char **out_sub_path, const char *path);
bool IsWindowsDrive(const char *name);
bool IsReservedMountName(const char *name);
bool IsValidMountName(const char *name);
Result CheckMountName(const char *name);
Result CheckMountNameAllowingReserved(const char *name);
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fs_filesystem_accessor.hpp"
#include "fs_user_mount_table.hpp"
namespace ams::fs::fsa {
Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs) {
auto accessor = std::make_unique<impl::FileSystemAccessor>(name, std::move(fs));
R_UNLESS(accessor != nullptr, fs::ResultAllocationMemoryFailedInRegisterA());
R_RETURN(impl::Register(std::move(accessor)));
}
Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs, std::unique_ptr<ICommonMountNameGenerator> &&generator) {
auto accessor = std::make_unique<impl::FileSystemAccessor>(name, std::move(fs), std::move(generator));
R_UNLESS(accessor != nullptr, fs::ResultAllocationMemoryFailedInRegisterB());
R_RETURN(impl::Register(std::move(accessor)));
}
Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs, std::unique_ptr<ICommonMountNameGenerator> &&generator, bool use_data_cache, bool use_path_cache, bool support_multi_commit) {
auto accessor = std::make_unique<impl::FileSystemAccessor>(name, std::move(fs), std::move(generator));
R_UNLESS(accessor != nullptr, fs::ResultAllocationMemoryFailedInRegisterB());
accessor->SetFileDataCacheAttachable(use_data_cache);
accessor->SetPathBasedFileDataCacheAttachable(use_path_cache);
accessor->SetMultiCommitSupported(support_multi_commit);
R_RETURN(impl::Register(std::move(accessor)));
}
void Unregister(const char *name) {
impl::Unregister(name);
}
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fs_directory_accessor.hpp"
#include "fs_filesystem_accessor.hpp"
namespace ams::fs {
namespace {
ALWAYS_INLINE impl::DirectoryAccessor *Get(DirectoryHandle handle) {
return reinterpret_cast<impl::DirectoryAccessor *>(handle.handle);
}
}
Result ReadDirectory(s64 *out_count, DirectoryEntry *out_entries, DirectoryHandle handle, s64 max_entries) {
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->Read(out_count, out_entries, max_entries), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_READ_DIRECTORY(out_count, max_entries)));
R_SUCCEED();
}
Result GetDirectoryEntryCount(s64 *out, DirectoryHandle handle) {
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->GetEntryCount(out), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_DIRECTORY_ENTRY_COUNT(out)));
R_SUCCEED();
}
void CloseDirectory(DirectoryHandle handle) {
AMS_FS_IMPL_ACCESS_LOG((delete Get(handle), ResultSuccess()), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE);
}
}

View File

@@ -1,94 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fs_file_accessor.hpp"
#include "fs_filesystem_accessor.hpp"
namespace ams::fs {
namespace {
ALWAYS_INLINE impl::FileAccessor *Get(FileHandle handle) {
return reinterpret_cast<impl::FileAccessor *>(handle.handle);
}
Result ReadFileImpl(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
R_TRY(Get(handle)->Read(out, offset, buffer, size, option));
R_SUCCEED();
}
}
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
size_t read_size;
AMS_FS_R_TRY(ReadFileImpl(std::addressof(read_size), handle, offset, buffer, size, option));
AMS_FS_R_UNLESS(read_size == size, fs::ResultOutOfRange());
R_SUCCEED();
}
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size) {
size_t read_size;
AMS_FS_R_TRY(ReadFileImpl(std::addressof(read_size), handle, offset, buffer, size, ReadOption()));
AMS_FS_R_UNLESS(read_size == size, fs::ResultOutOfRange());
R_SUCCEED();
}
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
AMS_FS_R_TRY(ReadFileImpl(out, handle, offset, buffer, size, option));
R_SUCCEED();
}
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size) {
AMS_FS_R_TRY(ReadFileImpl(out, handle, offset, buffer, size, ReadOption()));
R_SUCCEED();
}
Result GetFileSize(s64 *out, FileHandle handle) {
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->GetSize(out), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_FILE_SIZE(out)));
R_SUCCEED();
}
Result FlushFile(FileHandle handle) {
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->Flush(), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE));
R_SUCCEED();
}
Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) {
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->Write(offset, buffer, size, option), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_WRITE_FILE(option), offset, size));
R_SUCCEED();
}
Result SetFileSize(FileHandle handle, s64 size) {
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG(Get(handle)->SetSize(size), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_SIZE, size));
R_SUCCEED();
}
int GetFileOpenMode(FileHandle handle) {
const int mode = Get(handle)->GetOpenMode();
AMS_FS_IMPL_ACCESS_LOG(ResultSuccess(), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_OPEN_MODE, static_cast<u32>(mode));
return mode;
}
void CloseFile(FileHandle handle) {
AMS_FS_IMPL_ACCESS_LOG((delete Get(handle), ResultSuccess()), handle, AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE);
}
Result QueryRange(QueryRangeInfo *out, FileHandle handle, s64 offset, s64 size) {
AMS_FS_R_TRY(Get(handle)->OperateRange(out, sizeof(*out), OperationId::QueryRange, offset, size, nullptr, 0));
R_SUCCEED();
}
}

View File

@@ -1,230 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fs_filesystem_accessor.hpp"
#include "fs_file_accessor.hpp"
#include "fs_directory_accessor.hpp"
#include "fs_mount_utils.hpp"
#include "fs_user_mount_table.hpp"
namespace ams::fs {
Result CreateFile(const char *path, s64 size) {
R_RETURN(CreateFile(path, size, 0));
}
Result CreateFile(const char* path, s64 size, int option) {
impl::FileSystemAccessor *accessor;
const char *sub_path;
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path));
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(accessor->CreateFile(sub_path, size, option), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_SIZE, path, size));
R_SUCCEED();
}
Result DeleteFile(const char *path) {
impl::FileSystemAccessor *accessor;
const char *sub_path;
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path));
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(accessor->DeleteFile(sub_path), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path));
R_SUCCEED();
}
Result CreateDirectory(const char *path) {
impl::FileSystemAccessor *accessor;
const char *sub_path;
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path));
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(accessor->CreateDirectory(sub_path), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path));
R_SUCCEED();
}
Result DeleteDirectory(const char *path) {
impl::FileSystemAccessor *accessor;
const char *sub_path;
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path));
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(accessor->DeleteDirectory(sub_path), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path));
R_SUCCEED();
}
Result DeleteDirectoryRecursively(const char *path) {
impl::FileSystemAccessor *accessor;
const char *sub_path;
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path));
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(accessor->DeleteDirectoryRecursively(sub_path), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path));
R_SUCCEED();
}
Result RenameFile(const char *old_path, const char *new_path) {
impl::FileSystemAccessor *old_accessor;
impl::FileSystemAccessor *new_accessor;
const char *old_sub_path;
const char *new_sub_path;
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(old_accessor), std::addressof(old_sub_path), old_path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME, old_path, new_path));
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(new_accessor), std::addressof(new_sub_path), new_path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME, old_path, new_path));
auto rename_impl = [=]() -> Result {
R_UNLESS(old_accessor == new_accessor, fs::ResultRenameToOtherFileSystem());
R_TRY(old_accessor->RenameFile(old_sub_path, new_sub_path));
R_SUCCEED();
};
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(rename_impl(), nullptr, old_accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME, old_path, new_path));
R_SUCCEED();
}
Result RenameDirectory(const char *old_path, const char *new_path) {
impl::FileSystemAccessor *old_accessor;
impl::FileSystemAccessor *new_accessor;
const char *old_sub_path;
const char *new_sub_path;
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(old_accessor), std::addressof(old_sub_path), old_path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME, old_path, new_path));
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(new_accessor), std::addressof(new_sub_path), new_path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME, old_path, new_path));
auto rename_impl = [=]() -> Result {
R_UNLESS(old_accessor == new_accessor, fs::ResultRenameToOtherFileSystem());
R_TRY(old_accessor->RenameDirectory(old_sub_path, new_sub_path));
R_SUCCEED();
};
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(rename_impl(), nullptr, old_accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME, old_path, new_path));
R_SUCCEED();
}
Result GetEntryType(DirectoryEntryType *out, const char *path) {
impl::FileSystemAccessor *accessor;
const char *sub_path;
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path));
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(accessor->GetEntryType(out, sub_path), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_ENTRY_TYPE(out, path)));
R_SUCCEED();
}
Result OpenFile(FileHandle *out_file, const char *path, int mode) {
impl::FileSystemAccessor *accessor;
const char *sub_path;
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_OPEN_MODE, path, static_cast<u32>(mode)));
std::unique_ptr<impl::FileAccessor> file_accessor;
auto open_impl = [&]() -> Result {
R_UNLESS(out_file != nullptr, fs::ResultNullptrArgument());
R_TRY(accessor->OpenFile(std::addressof(file_accessor), sub_path, static_cast<OpenMode>(mode)));
R_SUCCEED();
};
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(open_impl(), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_OPEN_MODE, path, static_cast<u32>(mode)));
out_file->handle = file_accessor.release();
R_SUCCEED();
}
Result OpenDirectory(DirectoryHandle *out_dir, const char *path, int mode) {
impl::FileSystemAccessor *accessor;
const char *sub_path;
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_OPEN_MODE, path, static_cast<u32>(mode)));
std::unique_ptr<impl::DirectoryAccessor> dir_accessor;
auto open_impl = [&]() -> Result {
R_UNLESS(out_dir != nullptr, fs::ResultNullptrArgument());
R_TRY(accessor->OpenDirectory(std::addressof(dir_accessor), sub_path, static_cast<OpenDirectoryMode>(mode)));
R_SUCCEED();
};
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(open_impl(), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_OPEN_MODE, path, static_cast<u32>(mode)));
out_dir->handle = dir_accessor.release();
R_SUCCEED();
}
Result CleanDirectoryRecursively(const char *path) {
impl::FileSystemAccessor *accessor;
const char *sub_path;
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path), AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path));
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(accessor->CleanDirectoryRecursively(sub_path), nullptr, accessor, AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, path));
R_SUCCEED();
}
Result GetFreeSpaceSize(s64 *out, const char *path) {
/* Find the filesystem without access logging. */
impl::FileSystemAccessor *accessor;
const char *sub_path;
AMS_FS_R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
/* Get the total space size. */
AMS_FS_R_TRY(accessor->GetFreeSpaceSize(out, sub_path));
R_SUCCEED();
}
Result GetTotalSpaceSize(s64 *out, const char *path) {
/* Find the filesystem without access logging. */
impl::FileSystemAccessor *accessor;
const char *sub_path;
AMS_FS_R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
/* Get the total space size. */
AMS_FS_R_TRY(accessor->GetTotalSpaceSize(out, sub_path));
R_SUCCEED();
}
Result SetConcatenationFileAttribute(const char *path) {
impl::FileSystemAccessor *accessor;
const char *sub_path;
AMS_FS_R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
AMS_FS_R_TRY(accessor->QueryEntry(nullptr, 0, nullptr, 0, fsa::QueryId::SetConcatenationFileAttribute, sub_path));
R_SUCCEED();
}
Result OpenFile(FileHandle *out, std::unique_ptr<fsa::IFile> &&file, int mode) {
AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
auto file_accessor = std::make_unique<impl::FileAccessor>(std::move(file), nullptr, static_cast<OpenMode>(mode));
AMS_FS_R_UNLESS(file_accessor != nullptr, fs::ResultAllocationMemoryFailedNew());
out->handle = file_accessor.release();
R_SUCCEED();
}
namespace {
Result CommitImpl(const char *mount_name, const char *func_name) {
impl::FileSystemAccessor *accessor{};
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(impl::Find(std::addressof(accessor), mount_name), AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, mount_name));
AMS_FS_R_TRY(AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM_WITH_NAME(accessor->Commit(), nullptr, accessor, func_name, AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, mount_name));
R_SUCCEED();
}
}
Result Commit(const char *mount_name) {
R_RETURN(CommitImpl(mount_name, AMS_CURRENT_FUNCTION_NAME));
}
Result CommitSaveData(const char *mount_name) {
R_RETURN(CommitImpl(mount_name, AMS_CURRENT_FUNCTION_NAME));
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fs_filesystem_accessor.hpp"
#include "fs_file_accessor.hpp"
#include "fs_directory_accessor.hpp"
#include "fs_mount_utils.hpp"
#include "fs_user_mount_table.hpp"
namespace ams::fs {
namespace impl {
Result GetFileTimeStampRawForDebug(FileTimeStampRaw *out, const char *path) {
impl::FileSystemAccessor *accessor;
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
R_TRY(accessor->GetFileTimeStampRaw(out, sub_path));
R_SUCCEED();
}
}
Result GetFileTimeStamp(FileTimeStamp *out, const char *path) {
fs::FileTimeStampRaw raw;
AMS_FS_R_TRY(impl::GetFileTimeStampRawForDebug(std::addressof(raw), path));
static_assert(sizeof(raw) == sizeof(*out));
std::memcpy(out, std::addressof(raw), sizeof(raw));
R_SUCCEED();
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include "fs_user_mount_table.hpp"
#include "fs_mount_table.hpp"
#include "fs_filesystem_accessor.hpp"
namespace ams::fs::impl {
namespace {
constinit MountTable g_mount_table;
}
Result Register(std::unique_ptr<FileSystemAccessor> &&fs) {
R_RETURN(g_mount_table.Mount(std::move(fs)));
}
Result Find(FileSystemAccessor **out, const char *name) {
R_RETURN(g_mount_table.Find(out, name));
}
void Unregister(const char *name) {
g_mount_table.Unmount(name);
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright (c) 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::fs::impl {
class FileSystemAccessor;
Result Register(std::unique_ptr<FileSystemAccessor> &&fs);
Result Find(FileSystemAccessor **out, const char *name);
void Unregister(const char *name);
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright (c) 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::fs::impl {
class EventNotifierObjectAdapter final : public ::ams::fs::IEventNotifier, public ::ams::fs::impl::Newable {
private:
sf::SharedPointer<fssrv::sf::IEventNotifier> m_object;
public:
EventNotifierObjectAdapter(sf::SharedPointer<fssrv::sf::IEventNotifier> &&obj) : m_object(obj) { /* ... */ }
virtual ~EventNotifierObjectAdapter() { /* ... */ }
private:
virtual Result DoBindEvent(os::SystemEventType *out, os::EventClearMode clear_mode) override {
/* Get the handle. */
sf::NativeHandle handle;
AMS_FS_R_TRY(m_object->GetEventHandle(std::addressof(handle)));
/* Create the system event. */
os::AttachReadableHandleToSystemEvent(out, handle.GetOsHandle(), handle.IsManaged(), clear_mode);
handle.Detach();
R_SUCCEED();
}
};
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright (c) 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::fs::impl {
sf::SharedPointer<fssrv::sf::IFileSystemProxy> GetFileSystemProxyServiceObject();
sf::SharedPointer<fssrv::sf::IFileSystemProxyForLoader> GetFileSystemProxyForLoaderServiceObject();
}

View File

@@ -1,263 +0,0 @@
/*
* Copyright (c) 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::fs::impl {
class FileServiceObjectAdapter : public ::ams::fs::impl::Newable, public ::ams::fs::fsa::IFile {
NON_COPYABLE(FileServiceObjectAdapter);
NON_MOVEABLE(FileServiceObjectAdapter);
private:
sf::SharedPointer<fssrv::sf::IFile> m_x;
public:
explicit FileServiceObjectAdapter(sf::SharedPointer<fssrv::sf::IFile> &&o) : m_x(o) { /* ... */}
virtual ~FileServiceObjectAdapter() { /* ... */ }
public:
virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final {
s64 read_size = 0;
R_TRY(m_x->Read(std::addressof(read_size), offset, sf::OutNonSecureBuffer(buffer, size), static_cast<s64>(size), option));
*out = static_cast<size_t>(read_size);
R_SUCCEED();
}
virtual Result DoGetSize(s64 *out) override final {
R_RETURN(m_x->GetSize(out));
}
virtual Result DoFlush() override final {
R_RETURN(m_x->Flush());
}
virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final {
R_RETURN(m_x->Write(offset, sf::InNonSecureBuffer(buffer, size), static_cast<s64>(size), option));
}
virtual Result DoSetSize(s64 size) override final {
R_RETURN(m_x->SetSize(size));
}
virtual Result DoOperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final {
switch (op_id) {
case OperationId::Invalidate:
{
fs::QueryRangeInfo dummy_range_info;
R_RETURN(m_x->OperateRange(std::addressof(dummy_range_info), static_cast<s32>(op_id), offset, size));
}
case OperationId::QueryRange:
{
R_UNLESS(dst != nullptr, fs::ResultNullptrArgument());
R_UNLESS(dst_size == sizeof(fs::QueryRangeInfo), fs::ResultInvalidSize());
R_RETURN(m_x->OperateRange(reinterpret_cast<fs::QueryRangeInfo *>(dst), static_cast<s32>(op_id), offset, size));
}
default:
{
R_RETURN(m_x->OperateRangeWithBuffer(sf::OutNonSecureBuffer(dst, dst_size), sf::InNonSecureBuffer(src, src_size), static_cast<s32>(op_id), offset, size));
}
}
}
public:
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override final {
AMS_ABORT("Invalid GetDomainObjectId call");
}
};
class DirectoryServiceObjectAdapter : public ::ams::fs::impl::Newable, public ::ams::fs::fsa::IDirectory {
NON_COPYABLE(DirectoryServiceObjectAdapter);
NON_MOVEABLE(DirectoryServiceObjectAdapter);
private:
sf::SharedPointer<fssrv::sf::IDirectory> m_x;
public:
explicit DirectoryServiceObjectAdapter(sf::SharedPointer<fssrv::sf::IDirectory> &&o) : m_x(o) { /* ... */}
virtual ~DirectoryServiceObjectAdapter() { /* ... */ }
public:
virtual Result DoRead(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override final {
R_RETURN(m_x->Read(out_count, sf::OutBuffer(out_entries, max_entries * sizeof(*out_entries))));
}
virtual Result DoGetEntryCount(s64 *out) override final {
R_RETURN(m_x->GetEntryCount(out));
}
public:
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override final {
AMS_ABORT("Invalid GetDomainObjectId call");
}
};
class FileSystemServiceObjectAdapter : public ::ams::fs::impl::Newable, public ::ams::fs::fsa::IFileSystem {
NON_COPYABLE(FileSystemServiceObjectAdapter);
NON_MOVEABLE(FileSystemServiceObjectAdapter);
private:
sf::SharedPointer<fssrv::sf::IFileSystem> m_x;
public:
explicit FileSystemServiceObjectAdapter(sf::SharedPointer<fssrv::sf::IFileSystem> &&o) : m_x(o) { /* ... */}
virtual ~FileSystemServiceObjectAdapter() { /* ... */ }
sf::SharedPointer<fssrv::sf::IFileSystem> GetFileSystem() const { return m_x; }
private:
static Result GetPathForServiceObject(fssrv::sf::Path *out, const fs::Path &path) {
const size_t len = util::Strlcpy<char>(out->str, path.GetString(), sizeof(out->str));
R_UNLESS(len < sizeof(out->str), fs::ResultTooLongPath());
R_SUCCEED();
}
private:
virtual Result DoOpenFile(std::unique_ptr<fsa::IFile> *out_file, const fs::Path &path, OpenMode mode) override final {
/* Convert the path. */
fssrv::sf::Path fsp_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path));
/* Open the file. */
sf::SharedPointer<fssrv::sf::IFile> file;
R_TRY(m_x->OpenFile(std::addressof(file), fsp_path, mode));
/* Create the output fsa file. */
out_file->reset(new FileServiceObjectAdapter(std::move(file)));
R_UNLESS(out_file != nullptr, fs::ResultAllocationMemoryFailedNew());
R_SUCCEED();
}
virtual Result DoOpenDirectory(std::unique_ptr<fsa::IDirectory> *out_dir, const fs::Path &path, OpenDirectoryMode mode) override final {
/* Convert the path. */
fssrv::sf::Path fsp_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path));
/* Open the directory. */
sf::SharedPointer<fssrv::sf::IDirectory> dir;
R_TRY(m_x->OpenDirectory(std::addressof(dir), fsp_path, mode));
/* Create the output fsa directory. */
out_dir->reset(new DirectoryServiceObjectAdapter(std::move(dir)));
R_UNLESS(out_dir != nullptr, fs::ResultAllocationMemoryFailedNew());
R_SUCCEED();
}
virtual Result DoGetEntryType(DirectoryEntryType *out, const fs::Path &path) override final {
/* Convert the path. */
fssrv::sf::Path fsp_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path));
R_RETURN(m_x->GetEntryType(out, fsp_path));
}
virtual Result DoCommit() override final {
R_RETURN(m_x->Commit());
}
virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override final {
/* Convert the path. */
fssrv::sf::Path fsp_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path));
R_RETURN(m_x->CreateFile(fsp_path, size, flags));
}
virtual Result DoDeleteFile(const fs::Path &path) override final {
/* Convert the path. */
fssrv::sf::Path fsp_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path));
R_RETURN(m_x->DeleteFile(fsp_path));
}
virtual Result DoCreateDirectory(const fs::Path &path) override final {
/* Convert the path. */
fssrv::sf::Path fsp_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path));
R_RETURN(m_x->CreateDirectory(fsp_path));
}
virtual Result DoDeleteDirectory(const fs::Path &path) override final {
/* Convert the path. */
fssrv::sf::Path fsp_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path));
R_RETURN(m_x->DeleteDirectory(fsp_path));
}
virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override final {
/* Convert the path. */
fssrv::sf::Path fsp_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path));
R_RETURN(m_x->DeleteDirectoryRecursively(fsp_path));
}
virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override final {
/* Convert the path. */
fssrv::sf::Path fsp_old_path;
fssrv::sf::Path fsp_new_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_old_path), old_path));
R_TRY(GetPathForServiceObject(std::addressof(fsp_new_path), new_path));
R_RETURN(m_x->RenameFile(fsp_old_path, fsp_new_path));
}
virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override final {
/* Convert the path. */
fssrv::sf::Path fsp_old_path;
fssrv::sf::Path fsp_new_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_old_path), old_path));
R_TRY(GetPathForServiceObject(std::addressof(fsp_new_path), new_path));
R_RETURN(m_x->RenameDirectory(fsp_old_path, fsp_new_path));
}
virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override final {
/* Convert the path. */
fssrv::sf::Path fsp_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path));
R_RETURN(m_x->CleanDirectoryRecursively(fsp_path));
}
virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override final {
/* Convert the path. */
fssrv::sf::Path fsp_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path));
R_RETURN(m_x->GetFreeSpaceSize(out, fsp_path));
}
virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override final {
/* Convert the path. */
fssrv::sf::Path fsp_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path));
R_RETURN(m_x->GetTotalSpaceSize(out, fsp_path));
}
virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) override final {
/* Convert the path. */
fssrv::sf::Path fsp_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path));
R_RETURN(m_x->GetFileTimeStampRaw(out, fsp_path));
}
virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const fs::Path &path) override {
fssrv::sf::Path fsp_path;
R_TRY(GetPathForServiceObject(std::addressof(fsp_path), path));
R_RETURN(m_x->QueryEntry(sf::OutNonSecureBuffer(dst, dst_size), sf::InNonSecureBuffer(src, src_size), static_cast<s32>(query), fsp_path));
}
};
}

View File

@@ -1,34 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
namespace ams::fs::impl {
namespace {
constinit fssystem::ShaHashGeneratorFactorySelector g_sha_hash_generator_factory_selector;
}
fssystem::IHash256GeneratorFactorySelector *GetNcaHashGeneratorFactorySelector() {
return std::addressof(g_sha_hash_generator_factory_selector);
}
fssystem::IHash256GeneratorFactorySelector *GetSaveDataHashGeneratorFactorySelector() {
return std::addressof(g_sha_hash_generator_factory_selector);
}
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include <exosphere/pkg1.hpp>
namespace ams::fs::impl {
#define ADD_ENUM_CASE(v) case v: return #v
template<> const char *IdString::ToString<pkg1::KeyGeneration>(pkg1::KeyGeneration id) {
static_assert(pkg1::KeyGeneration_Current == pkg1::KeyGeneration_20_0_0);
switch (id) {
using enum pkg1::KeyGeneration;
case KeyGeneration_1_0_0: return "1.0.0-2.3.0";
case KeyGeneration_3_0_0: return "3.0.0";
case KeyGeneration_3_0_1: return "3.0.1-3.0.2";
case KeyGeneration_4_0_0: return "4.0.0-4.1.0";
case KeyGeneration_5_0_0: return "5.0.0-5.1.0";
case KeyGeneration_6_0_0: return "6.0.0-6.1.0";
case KeyGeneration_6_2_0: return "6.2.0";
case KeyGeneration_7_0_0: return "7.0.0-8.0.1";
case KeyGeneration_8_1_0: return "8.1.0-8.1.1";
case KeyGeneration_9_0_0: return "9.0.0-9.0.1";
case KeyGeneration_9_1_0: return "9.1.0-12.0.3";
case KeyGeneration_12_1_0: return "12.1.0";
case KeyGeneration_13_0_0: return "13.0.0-13.2.1";
case KeyGeneration_14_0_0: return "14.0.0-14.1.2";
case KeyGeneration_15_0_0: return "15.0.0-15.0.1";
case KeyGeneration_16_0_0: return "16.0.0-16.0.3";
case KeyGeneration_17_0_0: return "17.0.0-17.0.1";
case KeyGeneration_18_0_0: return "18.0.0-18.1.0";
case KeyGeneration_19_0_0: return "19.0.0-19.0.1";
case KeyGeneration_20_0_0: return "20.0.0-";
default: return "Unknown";
}
}
}

View File

@@ -1,121 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
#include <stratosphere/fssrv/fssrv_interface_adapters.hpp>
#include "fs_library.hpp"
#include "fs_file_system_service_object_adapter.hpp"
#include "../../fssrv/impl/fssrv_allocator_for_service_framework.hpp"
namespace ams::fs::impl {
#if !defined(ATMOSPHERE_OS_HORIZON)
namespace {
constexpr size_t SystemHeapSize = 8_MB;
alignas(os::MemoryPageSize) constinit u8 g_system_heap[SystemHeapSize];
ALWAYS_INLINE auto &GetSystemHeapAllocator() {
AMS_FUNCTION_LOCAL_STATIC(mem::StandardAllocator, s_system_heap_allocator, g_system_heap, sizeof(g_system_heap));
return s_system_heap_allocator;
}
constinit util::optional<fssrv::MemoryResourceFromStandardAllocator> g_system_heap_memory_resource;
void *AllocateForSystem(size_t size) { return g_system_heap_memory_resource->Allocate(size); }
void DeallocateForSystem(void *p, size_t size) { return g_system_heap_memory_resource->Deallocate(p, size); }
[[maybe_unused]] constexpr size_t BufferPoolSize = 6_MB;
[[maybe_unused]] constexpr size_t DeviceBufferSize = 8_MB;
[[maybe_unused]] constexpr size_t DeviceWorkBufferSize = os::MemoryPageSize;
[[maybe_unused]] constexpr size_t BufferManagerHeapSize = 14_MB;
constexpr size_t DeviceWorkBufferRequiredSize = 0x140;
static_assert(util::IsAligned(BufferManagerHeapSize, os::MemoryBlockUnitSize));
//alignas(os::MemoryPageSize) u8 g_buffer_pool[BufferPoolSize];
alignas(os::MemoryPageSize) u8 g_device_buffer[DeviceBufferSize];
alignas(os::MemoryPageSize) u8 g_device_work_buffer[DeviceWorkBufferSize];
//alignas(os::MemoryPageSize) u8 g_buffer_manager_heap[BufferManagerHeapSize];
//
//alignas(os::MemoryPageSize) u8 g_buffer_manager_work_buffer[64_KB];
/* TODO: Other work buffers. */
/* TODO: Implement pooled threads. */
// constexpr int PooledThreadCount = 12;
// constexpr size_t PooledThreadStackSize = 32_KB;
// fssystem::PooledThread g_pooled_threads[PooledThreadCount];
/* FileSystem creators. */
constinit util::optional<fssrv::fscreator::LocalFileSystemCreator> g_local_fs_creator;
constinit util::optional<fssrv::fscreator::SubDirectoryFileSystemCreator> g_subdir_fs_creator;
constinit fssrv::fscreator::FileSystemCreatorInterfaces g_fs_creator_interfaces = {};
Result InitializeFileSystemLibraryImpl() {
/* Set system allocator. */
fssystem::InitializeAllocator(::ams::fs::impl::Allocate, ::ams::fs::impl::Deallocate);
fssystem::InitializeAllocatorForSystem(::ams::fs::impl::AllocateForSystem, ::ams::fs::impl::DeallocateForSystem);
/* TODO: Many things. */
g_system_heap_memory_resource.emplace(std::addressof(GetSystemHeapAllocator()));
fssystem::InitializeBufferPool(reinterpret_cast<char *>(g_device_buffer), DeviceBufferSize, reinterpret_cast<char *>(g_device_work_buffer), DeviceWorkBufferRequiredSize);
/* Setup fscreators/interfaces. */
g_local_fs_creator.emplace(true);
g_subdir_fs_creator.emplace();
g_fs_creator_interfaces.local_fs_creator = std::addressof(*g_local_fs_creator);
g_fs_creator_interfaces.subdir_fs_creator = std::addressof(*g_subdir_fs_creator);
/* Initialize fssrv. */
const fssrv::FileSystemProxyConfiguration config = {
.m_fs_creator_interfaces = std::addressof(g_fs_creator_interfaces),
.m_base_storage_service_impl = nullptr /* TODO */,
.m_base_file_system_service_impl = nullptr /* TODO */,
.m_nca_file_system_service_impl = nullptr /* TODO */,
.m_save_data_file_system_service_impl = nullptr /* TODO */,
.m_access_failure_management_service_impl = nullptr /* TODO */,
.m_time_service_impl = nullptr /* TODO */,
.m_status_report_service_impl = nullptr /* TODO */,
.m_program_registry_service_impl = nullptr /* TODO */,
.m_access_log_service_impl = nullptr /* TODO */,
.m_debug_configuration_service_impl = nullptr /* TODO */,
};
fssrv::InitializeForFileSystemProxy(config);
R_SUCCEED();
}
class FileSystemLibraryInitializer {
public:
FileSystemLibraryInitializer() {
R_ABORT_UNLESS(InitializeFileSystemLibraryImpl());
}
};
}
#endif
void InitializeFileSystemLibrary() {
#if !defined(ATMOSPHERE_OS_HORIZON)
AMS_FUNCTION_LOCAL_STATIC(FileSystemLibraryInitializer, s_library_initializer);
AMS_UNUSED(s_library_initializer);
#endif
}
}

View File

@@ -1,23 +0,0 @@
/*
* Copyright (c) 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::fs::impl {
void InitializeFileSystemLibrary();
}

View File

@@ -1,103 +0,0 @@
/*
* Copyright (c) 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::fs::impl {
#if defined(ATMOSPHERE_OS_HORIZON)
class RemoteDeviceOperator {
private:
::FsDeviceOperator m_operator;
public:
RemoteDeviceOperator(::FsDeviceOperator &o) : m_operator(o) { /* ... */ }
virtual ~RemoteDeviceOperator() {
fsDeviceOperatorClose(std::addressof(m_operator));
}
public:
Result IsSdCardInserted(ams::sf::Out<bool> out) {
R_RETURN(fsDeviceOperatorIsSdCardInserted(std::addressof(m_operator), out.GetPointer()));
}
Result GetSdCardSpeedMode(ams::sf::Out<s64> out) {
R_RETURN(fsDeviceOperatorGetSdCardSpeedMode(std::addressof(m_operator), out.GetPointer()));
}
Result GetSdCardCid(ams::sf::OutBuffer out, s64 size) {
R_RETURN(fsDeviceOperatorGetSdCardCid(std::addressof(m_operator), out.GetPointer(), out.GetSize(), size));
}
Result GetSdCardUserAreaSize(ams::sf::Out<s64> out) {
R_RETURN(fsDeviceOperatorGetSdCardUserAreaSize(std::addressof(m_operator), out.GetPointer()));
}
Result GetSdCardProtectedAreaSize(ams::sf::Out<s64> out) {
R_RETURN(fsDeviceOperatorGetSdCardProtectedAreaSize(std::addressof(m_operator), out.GetPointer()));
}
Result GetAndClearSdCardErrorInfo(ams::sf::Out<fs::StorageErrorInfo> out_sei, ams::sf::Out<s64> out_size, ams::sf::OutBuffer out_buf, s64 size) {
static_assert(sizeof(::FsStorageErrorInfo) == sizeof(fs::StorageErrorInfo));
R_RETURN(fsDeviceOperatorGetAndClearSdCardErrorInfo(std::addressof(m_operator), reinterpret_cast<::FsStorageErrorInfo *>(out_sei.GetPointer()), out_size.GetPointer(), out_buf.GetPointer(), out_buf.GetSize(), size));
}
Result GetMmcCid(ams::sf::OutBuffer out, s64 size) {
R_RETURN(fsDeviceOperatorGetMmcCid(std::addressof(m_operator), out.GetPointer(), out.GetSize(), size));
}
Result GetMmcSpeedMode(ams::sf::Out<s64> out) {
R_RETURN(fsDeviceOperatorGetMmcSpeedMode(std::addressof(m_operator), out.GetPointer()));
}
Result GetMmcPatrolCount(ams::sf::Out<u32> out) {
R_RETURN(fsDeviceOperatorGetMmcPatrolCount(std::addressof(m_operator), out.GetPointer()));
}
Result GetAndClearMmcErrorInfo(ams::sf::Out<fs::StorageErrorInfo> out_sei, ams::sf::Out<s64> out_size, ams::sf::OutBuffer out_buf, s64 size) {
static_assert(sizeof(::FsStorageErrorInfo) == sizeof(fs::StorageErrorInfo));
R_RETURN(fsDeviceOperatorGetAndClearMmcErrorInfo(std::addressof(m_operator), reinterpret_cast<::FsStorageErrorInfo *>(out_sei.GetPointer()), out_size.GetPointer(), out_buf.GetPointer(), out_buf.GetSize(), size));
}
Result GetMmcExtendedCsd(ams::sf::OutBuffer out, s64 size) {
R_RETURN(fsDeviceOperatorGetMmcExtendedCsd(std::addressof(m_operator), out.GetPointer(), out.GetSize(), size));
}
Result IsGameCardInserted(ams::sf::Out<bool> out) {
R_RETURN(fsDeviceOperatorIsGameCardInserted(std::addressof(m_operator), out.GetPointer()));
}
Result GetGameCardHandle(ams::sf::Out<u32> out) {
static_assert(sizeof(::FsGameCardHandle) == sizeof(u32));
R_RETURN(fsDeviceOperatorGetGameCardHandle(std::addressof(m_operator), reinterpret_cast<::FsGameCardHandle *>(out.GetPointer())));
}
Result GetGameCardIdSet(ams::sf::OutBuffer out, s64 size) {
R_RETURN(fsDeviceOperatorGetGameCardIdSet(std::addressof(m_operator), out.GetPointer(), out.GetSize(), size));
}
Result GetGameCardErrorReportInfo(ams::sf::Out<fs::GameCardErrorReportInfo> out) {
static_assert(sizeof(::FsGameCardErrorReportInfo) == sizeof(fs::GameCardErrorReportInfo));
R_RETURN(fsDeviceOperatorGetGameCardErrorReportInfo(std::addressof(m_operator), reinterpret_cast<::FsGameCardErrorReportInfo *>(out.GetPointer())));
}
Result GetGameCardDeviceId(ams::sf::OutBuffer out, s64 size) {
R_RETURN(fsDeviceOperatorGetGameCardDeviceId(std::addressof(m_operator), out.GetPointer(), out.GetSize(), size));
}
};
static_assert(fssrv::sf::IsIDeviceOperator<RemoteDeviceOperator>);
#endif
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright (c) 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::fs::impl {
#if defined(ATMOSPHERE_OS_HORIZON)
class RemoteEventNotifier {
private:
::FsEventNotifier m_notifier;
public:
RemoteEventNotifier(::FsEventNotifier &n) : m_notifier(n) { /* ... */ }
virtual ~RemoteEventNotifier() {
fsEventNotifierClose(std::addressof(m_notifier));
}
public:
Result GetEventHandle(ams::sf::OutCopyHandle out) {
::Event e;
R_TRY(fsEventNotifierGetEventHandle(std::addressof(m_notifier), std::addressof(e), false));
out.SetValue(e.revent, true);
R_SUCCEED();
}
};
static_assert(fssrv::sf::IsIEventNotifier<RemoteEventNotifier>);
#endif
}

View File

@@ -1,623 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
namespace ams::fs {
namespace {
constexpr size_t DefaultPathBufferSize = fs::EntryNameLengthMax + 1;
consteval PathFlags DecodeFlags(const char *desc) {
PathFlags flags{};
while (*desc) {
switch (*(desc++)) {
case 'B':
flags.AllowBackslash();
break;
case 'E':
flags.AllowEmptyPath();
break;
case 'M':
flags.AllowMountName();
break;
case 'R':
flags.AllowRelativePath();
break;
case 'W':
flags.AllowWindowsPath();
break;
case 'C':
flags.AllowAllCharacters();
break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
return flags;
}
consteval size_t Strlen(const char *p) {
size_t len = 0;
while (p[len] != StringTraits::NullTerminator) {
++len;
}
return len;
}
//#define ENABLE_PRINT_FORMAT_TEST_DEBUGGING
#if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING)
template<u32 Expected, u32 Actual>
struct Print {
constexpr Print() {
if (std::is_constant_evaluated()) {
__builtin_unreachable();
}
}
};
template<u32 E = 0, u32 A = 0, size_t N = 0>
consteval void PrintResultMismatchImpl(u32 e, u32 a) {
if constexpr (N == 32) {
Print<E, A>{};
} else {
const bool is_e = (e & (1 << N)) != 0;
const bool is_a = (a & (1 << N)) != 0;
if (is_e) {
if (is_a) {
PrintResultMismatchImpl<E | (1 << N), A | (1 << N), N + 1>(e, a);
} else {
PrintResultMismatchImpl<E | (1 << N), A | (0 << N), N + 1>(e, a);
}
} else {
if (is_a) {
PrintResultMismatchImpl<E | (0 << N), A | (1 << N), N + 1>(e, a);
} else {
PrintResultMismatchImpl<E | (0 << N), A | (0 << N), N + 1>(e, a);
}
}
}
}
consteval void PrintResultMismatch(const Result &lhs, const Result &rhs) {
PrintResultMismatchImpl(lhs.GetDescription(), rhs.GetDescription());
}
template<size_t Index, char Expected, char Actual>
struct PrintMismatchChar {
constexpr PrintMismatchChar() {
if (std::is_constant_evaluated()) {
__builtin_unreachable();
}
}
};
template<size_t Ix, char Expected, size_t C = 0>
consteval void PrintCharacterMismatch(char c) {
if (c == static_cast<char>(C)) {
PrintMismatchChar<Ix, Expected, static_cast<char>(C)>{};
return;
}
if constexpr (C < std::numeric_limits<unsigned char>::max()) {
PrintCharacterMismatch<Ix, Expected, C + 1>(c);
}
}
template<size_t Ix, char C = 0>
consteval void PrintCharacterMismatch(char c, char c2) {
if (c == static_cast<char>(C)) {
PrintCharacterMismatch<Ix, static_cast<char>(C)>(c2);
return;
}
if constexpr (C < std::numeric_limits<unsigned char>::max()) {
PrintCharacterMismatch<Ix, C + 1>(c, c2);
}
}
template<size_t Ix = 0>
consteval void PrintCharacterMismatch(size_t ix, char c, char c2) {
if (Ix == ix) {
PrintCharacterMismatch<Ix>(c, c2);
return;
}
if constexpr (Ix <= DefaultPathBufferSize) {
PrintCharacterMismatch<Ix + 1>(ix, c, c2);
}
}
#endif
consteval bool TestNormalizedImpl(const char *path, const PathFlags &flags, size_t buffer_size, const char *normalized, Result expected_result) {
/* Allocate a buffer to normalize into. */
char *buffer = new char[buffer_size];
ON_SCOPE_EXIT { delete[] buffer; };
buffer[buffer_size - 1] = '\xcc';
/* Perform normalization. */
const Result actual_result = PathFormatter::Normalize(buffer, buffer_size, path, Strlen(path) + 1, flags);
/* Check that the expected result matches the actual. */
if (actual_result.GetValue() != expected_result.GetValue()) {
#if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING)
PrintResultMismatch(expected_result.GetValue(), actual_result.GetValue());
#endif
return false;
}
/* Check that the expected string matches the actual. */
for (size_t i = 0; i < buffer_size; ++i) {
if (normalized[i] != StringTraits::NullTerminator || R_SUCCEEDED(expected_result)) {
if (buffer[i] != normalized[i]) {
#if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING)
PrintCharacterMismatch(i, normalized[i], buffer[i]);
#endif
return false;
}
}
if (normalized[i] == StringTraits::NullTerminator || buffer[i] == StringTraits::NullTerminator) {
break;
}
}
return true;
}
struct NormalizeTestData {
const char *path;
const char *flag_desc;
const char *normalized;
Result result;
size_t buffer_size = DefaultPathBufferSize;
};
template<size_t N, size_t Ix = 0>
consteval bool DoNormalizeTests(const NormalizeTestData (&tests)[N]) {
if constexpr (Ix >= N) {
return true;
}
const auto &test = tests[Ix];
if (!TestNormalizedImpl(test.path, DecodeFlags(test.flag_desc), test.buffer_size, test.normalized, test.result)) {
return false;
}
if constexpr (Ix < N) {
return DoNormalizeTests<N, Ix + 1>(tests);
} else {
AMS_ASSUME(false);
}
}
consteval bool TestNormalizeEmptyPath() {
constexpr NormalizeTestData Tests[] = {
{ "", "", "", fs::ResultInvalidPathFormat() },
{ "", "E", "", ResultSuccess() },
{ "/aa/bb/../cc", "E", "/aa/cc", ResultSuccess() },
};
return DoNormalizeTests(Tests);
}
static_assert(TestNormalizeEmptyPath());
consteval bool TestNormalizeMountName() {
constexpr NormalizeTestData Tests[] = {
{ "mount:/aa/bb", "", "", fs::ResultInvalidPathFormat() },
{ "mount:/aa/bb", "W", "", fs::ResultInvalidPathFormat() },
{ "mount:/aa/bb", "M", "mount:/aa/bb", ResultSuccess() },
{ "mount:/aa/./bb", "M", "mount:/aa/bb", ResultSuccess() },
{ "mount:\\aa\\bb", "M", "mount:", fs::ResultInvalidPathFormat() },
{ "m:/aa/bb", "M", "", fs::ResultInvalidPathFormat() },
{ "mo>unt:/aa/bb", "M", "", fs::ResultInvalidCharacter() },
{ "moun?t:/aa/bb", "M", "", fs::ResultInvalidCharacter() },
{ "mo&unt:/aa/bb", "M", "mo&unt:/aa/bb", ResultSuccess() },
{ "/aa/./bb", "M", "/aa/bb", ResultSuccess() },
{ "mount/aa/./bb", "M", "", fs::ResultInvalidPathFormat() }
};
return DoNormalizeTests(Tests);
}
static_assert(TestNormalizeMountName());
consteval bool TestNormalizeWindowsPath() {
constexpr NormalizeTestData Tests[] = {
{ "c:/aa/bb", "", "", fs::ResultInvalidPathFormat() },
{ "c:\\aa\\bb", "", "", fs::ResultInvalidCharacter() },
{ "\\\\host\\share", "", "", fs::ResultInvalidCharacter() },
{ "\\\\.\\c:\\", "", "", fs::ResultInvalidCharacter() },
{ "\\\\.\\c:/aa/bb/.", "", "", fs::ResultInvalidCharacter() },
{ "\\\\?\\c:\\", "", "", fs::ResultInvalidCharacter() },
{ "mount:\\\\host\\share\\aa\\bb", "M", "mount:", fs::ResultInvalidCharacter() },
{ "mount:\\\\host/share\\aa\\bb", "M", "mount:", fs::ResultInvalidCharacter() },
{ "c:\\aa\\..\\..\\..\\bb", "W", "c:/bb", ResultSuccess() },
{ "mount:/\\\\aa\\..\\bb", "MW", "mount:", fs::ResultInvalidPathFormat() },
{ "mount:/c:\\aa\\..\\bb", "MW", "mount:c:/bb", ResultSuccess() },
{ "mount:/aa/bb", "MW", "mount:/aa/bb", ResultSuccess() },
{ "/mount:/aa/bb", "MW", "/", fs::ResultInvalidCharacter() },
{ "/mount:/aa/bb", "W", "/", fs::ResultInvalidCharacter() },
{ "a:aa/../bb", "MW", "a:aa/bb", ResultSuccess() },
{ "a:aa\\..\\bb", "MW", "a:aa/bb", ResultSuccess() },
{ "/a:aa\\..\\bb", "W", "/", fs::ResultInvalidCharacter() },
{ "\\\\?\\c:\\.\\aa", "W", "\\\\?\\c:/aa", ResultSuccess() },
{ "\\\\.\\c:\\.\\aa", "W", "\\\\.\\c:/aa", ResultSuccess() },
{ "\\\\.\\mount:\\.\\aa", "W", "\\\\./", fs::ResultInvalidCharacter() },
{ "\\\\./.\\aa", "W", "\\\\./aa", ResultSuccess() },
{ "\\\\/aa", "W", "", fs::ResultInvalidPathFormat() },
{ "\\\\\\aa", "W", "", fs::ResultInvalidPathFormat() },
{ "\\\\", "W", "/", ResultSuccess() },
{ "\\\\host\\share", "W", "\\\\host\\share/", ResultSuccess() },
{ "\\\\host\\share\\path", "W", "\\\\host\\share/path", ResultSuccess() },
{ "\\\\host\\share\\path\\aa\\bb\\..\\cc\\.", "W", "\\\\host\\share/path/aa/cc", ResultSuccess() },
{ "\\\\host\\", "W", "", fs::ResultInvalidPathFormat() },
{ "\\\\ho$st\\share\\path", "W", "", fs::ResultInvalidCharacter() },
{ "\\\\host:\\share\\path", "W", "", fs::ResultInvalidCharacter() },
{ "\\\\..\\share\\path", "W", "", fs::ResultInvalidPathFormat() },
{ "\\\\host\\s:hare\\path", "W", "", fs::ResultInvalidCharacter() },
{ "\\\\host\\.\\path", "W", "", fs::ResultInvalidPathFormat() },
{ "\\\\host\\..\\path", "W", "", fs::ResultInvalidPathFormat() },
{ "\\\\host\\sha:re", "W", "", fs::ResultInvalidCharacter() },
{ ".\\\\host\\share", "RW", "..\\\\host\\share/", ResultSuccess() }
};
return DoNormalizeTests(Tests);
}
static_assert(TestNormalizeWindowsPath());
consteval bool TestNormalizeRelativePath() {
constexpr NormalizeTestData Tests[] = {
{ "./aa/bb", "", "", fs::ResultInvalidPathFormat() },
{ "./aa/bb/../cc", "R", "./aa/cc", ResultSuccess() },
{ ".\\aa/bb/../cc", "R", "..", fs::ResultInvalidCharacter() },
{ ".", "R", ".", ResultSuccess() },
{ "../aa/bb", "R", "", fs::ResultDirectoryUnobtainable() },
{ "/aa/./bb", "R", "/aa/bb", ResultSuccess() },
{ "mount:./aa/bb", "MR", "mount:./aa/bb", ResultSuccess() },
{ "mount:./aa/./bb", "MR", "mount:./aa/bb", ResultSuccess() },
{ "mount:./aa/bb", "M", "mount:", fs::ResultInvalidPathFormat() }
};
return DoNormalizeTests(Tests);
}
static_assert(TestNormalizeRelativePath());
consteval bool TestNormalizeBackslash() {
constexpr NormalizeTestData Tests[] = {
{ "\\aa\\bb\\..\\cc", "", "", fs::ResultInvalidPathFormat() },
{ "\\aa\\bb\\..\\cc", "B", "", fs::ResultInvalidPathFormat() },
{ "/aa\\bb\\..\\cc", "", "", fs::ResultInvalidCharacter() },
{ "/aa\\bb\\..\\cc", "B", "/cc", ResultSuccess() },
{ "/aa\\bb\\cc", "", "", fs::ResultInvalidCharacter() },
{ "/aa\\bb\\cc", "B", "/aa\\bb\\cc", ResultSuccess() },
{ "\\\\host\\share\\path\\aa\\bb\\cc", "W", "\\\\host\\share/path/aa/bb/cc", ResultSuccess() },
{ "\\\\host\\share\\path\\aa\\bb\\cc", "WB", "\\\\host\\share/path/aa/bb/cc", ResultSuccess() },
{ "/aa/bb\\../cc/..\\dd\\..\\ee/..", "", "", fs::ResultInvalidCharacter() },
{ "/aa/bb\\../cc/..\\dd\\..\\ee/..", "B", "/aa", ResultSuccess() }
};
return DoNormalizeTests(Tests);
}
static_assert(TestNormalizeBackslash());
consteval bool TestNormalizeAllowAllChars() {
constexpr NormalizeTestData Tests[] = {
{ "/aa/b:b/cc", "", "/aa/", fs::ResultInvalidCharacter() },
{ "/aa/b*b/cc", "", "/aa/", fs::ResultInvalidCharacter() },
{ "/aa/b?b/cc", "", "/aa/", fs::ResultInvalidCharacter() },
{ "/aa/b<b/cc", "", "/aa/", fs::ResultInvalidCharacter() },
{ "/aa/b>b/cc", "", "/aa/", fs::ResultInvalidCharacter() },
{ "/aa/b|b/cc", "", "/aa/", fs::ResultInvalidCharacter() },
{ "/aa/b:b/cc", "C", "/aa/b:b/cc", ResultSuccess() },
{ "/aa/b*b/cc", "C", "/aa/b*b/cc", ResultSuccess() },
{ "/aa/b?b/cc", "C", "/aa/b?b/cc", ResultSuccess() },
{ "/aa/b<b/cc", "C", "/aa/b<b/cc", ResultSuccess() },
{ "/aa/b>b/cc", "C", "/aa/b>b/cc", ResultSuccess() },
{ "/aa/b|b/cc", "C", "/aa/b|b/cc", ResultSuccess() },
{ "/aa/b'b/cc", "", "/aa/b'b/cc", ResultSuccess() },
{ "/aa/b\"b/cc", "", "/aa/b\"b/cc", ResultSuccess() },
{ "/aa/b(b/cc", "", "/aa/b(b/cc", ResultSuccess() },
{ "/aa/b)b/cc", "", "/aa/b)b/cc", ResultSuccess() },
{ "/aa/b'b/cc", "C", "/aa/b'b/cc", ResultSuccess() },
{ "/aa/b\"b/cc", "C", "/aa/b\"b/cc", ResultSuccess() },
{ "/aa/b(b/cc", "C", "/aa/b(b/cc", ResultSuccess() },
{ "/aa/b)b/cc", "C", "/aa/b)b/cc", ResultSuccess() },
{ "mount:/aa/b<b/cc", "MC", "mount:/aa/b<b/cc", ResultSuccess() },
{ "mo>unt:/aa/bb/cc", "MC", "", fs::ResultInvalidCharacter() }
};
return DoNormalizeTests(Tests);
}
static_assert(TestNormalizeAllowAllChars());
consteval bool TestNormalizeAll() {
constexpr NormalizeTestData Tests[] = {
{ "mount:./aa/bb", "WRM", "mount:./aa/bb", ResultSuccess() },
{ "mount:./aa/bb\\cc/dd", "WRM", "mount:./aa/bb/cc/dd", ResultSuccess() },
{ "mount:./aa/bb\\cc/dd", "WRMB", "mount:./aa/bb/cc/dd", ResultSuccess() },
{ "mount:./.c:/aa/bb", "RM", "mount:./", fs::ResultInvalidCharacter() },
{ "mount:.c:/aa/bb", "WRM", "mount:./", fs::ResultInvalidCharacter() },
{ "mount:./cc:/aa/bb", "WRM", "mount:./", fs::ResultInvalidCharacter() },
{ "mount:./\\\\host\\share/aa/bb", "MW", "mount:", fs::ResultInvalidPathFormat() },
{ "mount:./\\\\host\\share/aa/bb", "WRM", "mount:.\\\\host\\share/aa/bb", ResultSuccess() },
{ "mount:.\\\\host\\share/aa/bb", "WRM", "mount:..\\\\host\\share/aa/bb", ResultSuccess() },
{ "mount:..\\\\host\\share/aa/bb", "WRM", "mount:.", fs::ResultDirectoryUnobtainable() },
{ ".\\\\host\\share/aa/bb", "WRM", "..\\\\host\\share/aa/bb", ResultSuccess() },
{ "..\\\\host\\share/aa/bb", "WRM", ".", fs::ResultDirectoryUnobtainable() },
{ "mount:\\\\host\\share/aa/bb", "MW", "mount:\\\\host\\share/aa/bb", ResultSuccess() },
{ "mount:\\aa\\bb", "BM", "mount:", fs::ResultInvalidPathFormat() },
{ "mount:/aa\\bb", "BM", "mount:/aa\\bb", ResultSuccess() },
{ ".//aa/bb", "RW", "./aa/bb", ResultSuccess() },
{ "./aa/bb", "R", "./aa/bb", ResultSuccess() },
{ "./c:/aa/bb", "RW", "./", fs::ResultInvalidCharacter() },
{ "mount:./aa/b:b\\cc/dd", "WRMBC", "mount:./aa/b:b/cc/dd", ResultSuccess() }
};
return DoNormalizeTests(Tests);
}
static_assert(TestNormalizeAll());
consteval bool TestNormalizeSmallBuffer() {
constexpr NormalizeTestData Tests[] = {
{ "/aa/bb", "M", "", fs::ResultTooLongPath(), 1},
{ "mount:/aa/bb", "MR", "", fs::ResultTooLongPath(), 6 },
{ "mount:/aa/bb", "MR", "mount:", fs::ResultTooLongPath(), 7 },
{ "aa/bb", "MR", "./", fs::ResultTooLongPath(), 3 },
{ "\\\\host\\share", "W", "\\\\host\\share", fs::ResultTooLongPath(), 13 }
};
return DoNormalizeTests(Tests);
}
static_assert(TestNormalizeSmallBuffer());
consteval bool TestIsNormalizedImpl(const char *path, const PathFlags &flags, bool expected_normalized, size_t expected_size, Result expected_result) {
/* Perform normalization checking. */
bool actual_normalized;
size_t actual_size;
const Result actual_result = PathFormatter::IsNormalized(std::addressof(actual_normalized), std::addressof(actual_size), path, flags);
/* Check that the expected result matches the actual. */
if (actual_result.GetValue() != expected_result.GetValue()) {
#if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING)
PrintResultMismatch(expected_result.GetValue(), actual_result.GetValue());
#endif
return false;
}
/* Check that the expected output matches the actual. */
if (R_SUCCEEDED(expected_result)) {
if (expected_normalized != actual_normalized) {
#if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING)
PrintResultMismatchImpl(static_cast<u32>(expected_normalized), static_cast<u32>(actual_normalized));
#endif
return false;
}
if (expected_normalized) {
if (expected_size != actual_size) {
#if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING)
PrintResultMismatchImpl(static_cast<u32>(expected_size), static_cast<u32>(actual_size));
#endif
return false;
}
}
}
return true;
}
struct IsNormalizedTestData {
const char *path;
const char *flag_desc;
bool normalized;
size_t len;
Result result;
};
template<size_t N, size_t Ix = 0>
consteval bool DoIsNormalizedTests(const IsNormalizedTestData (&tests)[N]) {
if constexpr (Ix >= N) {
return true;
}
const auto &test = tests[Ix];
if (!TestIsNormalizedImpl(test.path, DecodeFlags(test.flag_desc), test.normalized, test.len, test.result)) {
return false;
}
if constexpr (Ix < N) {
return DoIsNormalizedTests<N, Ix + 1>(tests);
} else {
AMS_ASSUME(false);
}
}
consteval bool TestIsNormalizedEmptyPath() {
constexpr IsNormalizedTestData Tests[] = {
{ "", "", false, 0, fs::ResultInvalidPathFormat() },
{ "", "E", true, 0, ResultSuccess() },
{ "/aa/bb/../cc", "E", false, 0, ResultSuccess() }
};
return DoIsNormalizedTests(Tests);
}
static_assert(TestIsNormalizedEmptyPath());
consteval bool TestIsNormalizedMountName() {
constexpr IsNormalizedTestData Tests[] = {
{ "mount:/aa/bb", "", false, 0, fs::ResultInvalidPathFormat() },
{ "mount:/aa/bb", "W", false, 0, fs::ResultInvalidPathFormat() },
{ "mount:/aa/bb", "M", true, 12, ResultSuccess() },
{ "mount:/aa/./bb", "M", false, 6, ResultSuccess() },
{ "mount:\\aa\\bb", "M", false, 0, fs::ResultInvalidPathFormat() },
{ "m:/aa/bb", "M", false, 0, fs::ResultInvalidPathFormat() },
{ "mo>unt:/aa/bb", "M", false, 0, fs::ResultInvalidCharacter() },
{ "moun?t:/aa/bb", "M", false, 0, fs::ResultInvalidCharacter() },
{ "mo&unt:/aa/bb", "M", true, 13, ResultSuccess() },
{ "/aa/./bb", "M", false, 0, ResultSuccess() },
{ "mount/aa/./bb", "M", false, 0, fs::ResultInvalidPathFormat() }
};
return DoIsNormalizedTests(Tests);
}
static_assert(TestIsNormalizedMountName());
consteval bool TestIsNormalizedWindowsPath() {
constexpr IsNormalizedTestData Tests[] = {
{ "c:/aa/bb", "", false, 0, fs::ResultInvalidPathFormat() },
{ "c:\\aa\\bb", "", false, 0, fs::ResultInvalidPathFormat() },
{ "\\\\host\\share", "", false, 0, fs::ResultInvalidPathFormat() },
{ "\\\\.\\c:\\", "", false, 0, fs::ResultInvalidPathFormat() },
{ "\\\\.\\c:/aa/bb/.", "", false, 0, fs::ResultInvalidPathFormat() },
{ "\\\\?\\c:\\", "", false, 0, fs::ResultInvalidPathFormat() },
{ "mount:\\\\host\\share\\aa\\bb", "M", false, 0, fs::ResultInvalidPathFormat() },
{ "mount:\\\\host/share\\aa\\bb", "M", false, 0, fs::ResultInvalidPathFormat() },
{ "c:\\aa\\..\\..\\..\\bb", "W", false, 0, ResultSuccess() },
{ "mount:/\\\\aa\\..\\bb", "MW", false, 0, ResultSuccess() },
{ "mount:/c:\\aa\\..\\bb", "MW", false, 0, ResultSuccess() },
{ "mount:/aa/bb", "MW", true, 12, ResultSuccess() },
{ "/mount:/aa/bb", "MW", false, 0, fs::ResultInvalidCharacter() },
{ "/mount:/aa/bb", "W", false, 0, fs::ResultInvalidCharacter() },
{ "a:aa/../bb", "MW", false, 8, ResultSuccess() },
{ "a:aa\\..\\bb", "MW", false, 0, ResultSuccess() },
{ "/a:aa\\..\\bb", "W", false, 0, ResultSuccess() },
{ "\\\\?\\c:\\.\\aa", "W", false, 0, ResultSuccess() },
{ "\\\\.\\c:\\.\\aa", "W", false, 0, ResultSuccess() },
{ "\\\\.\\mount:\\.\\aa", "W", false, 0, ResultSuccess() },
{ "\\\\./.\\aa", "W", false, 0, ResultSuccess() },
{ "\\\\/aa", "W", false, 0, fs::ResultInvalidPathFormat() },
{ "\\\\\\aa", "W", false, 0, fs::ResultInvalidPathFormat() },
{ "\\\\", "W", false, 0, ResultSuccess() },
{ "\\\\host\\share", "W", false, 0, ResultSuccess() },
{ "\\\\host\\share\\path", "W", false, 0, ResultSuccess() },
{ "\\\\host\\share\\path\\aa\\bb\\..\\cc\\.", "W", false, 0, ResultSuccess() },
{ "\\\\host\\", "W", false, 0, fs::ResultInvalidPathFormat() },
{ "\\\\ho$st\\share\\path", "W", false, 0, fs::ResultInvalidCharacter() },
{ "\\\\host:\\share\\path", "W", false, 0, fs::ResultInvalidCharacter() },
{ "\\\\..\\share\\path", "W", false, 0, fs::ResultInvalidPathFormat() },
{ "\\\\host\\s:hare\\path", "W", false, 0, fs::ResultInvalidCharacter() },
{ "\\\\host\\.\\path", "W", false, 0, fs::ResultInvalidPathFormat() },
{ "\\\\host\\..\\path", "W", false, 0, fs::ResultInvalidPathFormat() },
{ "\\\\host\\sha:re", "W", false, 0, fs::ResultInvalidCharacter() },
{ ".\\\\host\\share", "RW", false, 0, ResultSuccess() }
};
return DoIsNormalizedTests(Tests);
}
static_assert(TestIsNormalizedWindowsPath());
consteval bool TestIsNormalizedRelativePath() {
constexpr IsNormalizedTestData Tests[] = {
{ "./aa/bb", "", false, 0, fs::ResultInvalidPathFormat() },
{ "./aa/bb/../cc", "R", false, 1, ResultSuccess() },
{ ".\\aa/bb/../cc", "R", false, 0, ResultSuccess() },
{ ".", "R", true, 1, ResultSuccess() },
{ "../aa/bb", "R", false, 0, fs::ResultDirectoryUnobtainable() },
{ "/aa/./bb", "R", false, 0, ResultSuccess() },
{ "mount:./aa/bb", "MR", true, 13, ResultSuccess() },
{ "mount:./aa/./bb", "MR", false, 7, ResultSuccess() },
{ "mount:./aa/bb", "M", false, 0, fs::ResultInvalidPathFormat() }
};
return DoIsNormalizedTests(Tests);
}
static_assert(TestIsNormalizedRelativePath());
consteval bool TestIsNormalizedBackslash() {
constexpr IsNormalizedTestData Tests[] = {
{ "\\aa\\bb\\..\\cc", "", false, 0, fs::ResultInvalidPathFormat() },
{ "\\aa\\bb\\..\\cc", "B", false, 0, fs::ResultInvalidPathFormat() },
{ "/aa\\bb\\..\\cc", "", false, 0, fs::ResultInvalidCharacter() },
{ "/aa\\bb\\..\\cc", "B", false, 0, ResultSuccess() },
{ "/aa\\bb\\cc", "", false, 0, fs::ResultInvalidCharacter() },
{ "/aa\\bb\\cc", "B", true, 9, ResultSuccess() },
{ "\\\\host\\share\\path\\aa\\bb\\cc", "W", false, 0, ResultSuccess() },
{ "\\\\host\\share\\path\\aa\\bb\\cc", "WB", false, 0, ResultSuccess() },
{ "/aa/bb\\../cc/..\\dd\\..\\ee/..", "", false, 0, fs::ResultInvalidCharacter() },
{ "/aa/bb\\../cc/..\\dd\\..\\ee/..", "B", false, 0, ResultSuccess() }
};
return DoIsNormalizedTests(Tests);
}
static_assert(TestIsNormalizedBackslash());
consteval bool TestIsNormalizedAllowAllCharacters() {
constexpr IsNormalizedTestData Tests[] = {
{ "/aa/b:b/cc", "", false, 0, fs::ResultInvalidCharacter() },
{ "/aa/b*b/cc", "", false, 0, fs::ResultInvalidCharacter() },
{ "/aa/b?b/cc", "", false, 0, fs::ResultInvalidCharacter() },
{ "/aa/b<b/cc", "", false, 0, fs::ResultInvalidCharacter() },
{ "/aa/b>b/cc", "", false, 0, fs::ResultInvalidCharacter() },
{ "/aa/b|b/cc", "", false, 0, fs::ResultInvalidCharacter() },
{ "/aa/b:b/cc", "C", true, 10, ResultSuccess() },
{ "/aa/b*b/cc", "C", true, 10, ResultSuccess() },
{ "/aa/b?b/cc", "C", true, 10, ResultSuccess() },
{ "/aa/b<b/cc", "C", true, 10, ResultSuccess() },
{ "/aa/b>b/cc", "C", true, 10, ResultSuccess() },
{ "/aa/b|b/cc", "C", true, 10, ResultSuccess() },
{ "/aa/b'b/cc", "", true, 10, ResultSuccess() },
{ "/aa/b\"b/cc", "", true, 10, ResultSuccess() },
{ "/aa/b(b/cc", "", true, 10, ResultSuccess() },
{ "/aa/b)b/cc", "", true, 10, ResultSuccess() },
{ "/aa/b'b/cc", "C", true, 10, ResultSuccess() },
{ "/aa/b\"b/cc", "C", true, 10, ResultSuccess() },
{ "/aa/b(b/cc", "C", true, 10, ResultSuccess() },
{ "/aa/b)b/cc", "C", true, 10, ResultSuccess() },
{ "mount:/aa/b<b/cc", "MC", true, 16, ResultSuccess() },
{ "mo>unt:/aa/bb/cc", "MC", false, 0, fs::ResultInvalidCharacter() }
};
return DoIsNormalizedTests(Tests);
}
static_assert(TestIsNormalizedAllowAllCharacters());
consteval bool TestIsNormalizedAll() {
constexpr IsNormalizedTestData Tests[] = {
{ "mount:./aa/bb", "WRM", true, 13, ResultSuccess() },
{ "mount:./aa/bb\\cc/dd", "WRM", false, 0, ResultSuccess() },
{ "mount:./aa/bb\\cc/dd", "WRMB", true, 19, ResultSuccess() },
{ "mount:./.c:/aa/bb", "RM", false, 0, fs::ResultInvalidCharacter() },
{ "mount:.c:/aa/bb", "WRM", false, 0, ResultSuccess() },
{ "mount:./cc:/aa/bb", "WRM", false, 0, fs::ResultInvalidCharacter() },
{ "mount:./\\\\host\\share/aa/bb", "MW", false, 0, fs::ResultInvalidPathFormat() },
{ "mount:./\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() },
{ "mount:.\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() },
{ "mount:..\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() },
{ ".\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() },
{ "..\\\\host\\share/aa/bb", "WRM", false, 0, ResultSuccess() },
{ "mount:\\\\host\\share/aa/bb", "MW", true, 24, ResultSuccess() },
{ "mount:\\aa\\bb", "BM", false, 0, fs::ResultInvalidPathFormat() },
{ "mount:/aa\\bb", "BM", true, 12, ResultSuccess() },
{ ".//aa/bb", "RW", false, 1, ResultSuccess() },
{ "./aa/bb", "R", true, 7, ResultSuccess() },
{ "./c:/aa/bb", "RW", false, 0, fs::ResultInvalidCharacter() },
{ "mount:./aa/b:b\\cc/dd", "WRMBC", true, 20, ResultSuccess() }
};
return DoIsNormalizedTests(Tests);
}
static_assert(TestIsNormalizedAll());
}
}

View File

@@ -1,394 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
namespace ams::fs {
namespace {
constexpr size_t DefaultPathBufferSize = fs::EntryNameLengthMax + 1;
//#define ENABLE_PRINT_FORMAT_TEST_DEBUGGING
#if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING)
template<u32 Expected, u32 Actual>
struct Print {
constexpr Print() {
if (std::is_constant_evaluated()) {
__builtin_unreachable();
}
}
};
template<u32 E = 0, u32 A = 0, size_t N = 0>
consteval void PrintResultMismatchImpl(u32 e, u32 a) {
if constexpr (N == 32) {
Print<E, A>{};
} else {
const bool is_e = (e & (1 << N)) != 0;
const bool is_a = (a & (1 << N)) != 0;
if (is_e) {
if (is_a) {
PrintResultMismatchImpl<E | (1 << N), A | (1 << N), N + 1>(e, a);
} else {
PrintResultMismatchImpl<E | (1 << N), A | (0 << N), N + 1>(e, a);
}
} else {
if (is_a) {
PrintResultMismatchImpl<E | (0 << N), A | (1 << N), N + 1>(e, a);
} else {
PrintResultMismatchImpl<E | (0 << N), A | (0 << N), N + 1>(e, a);
}
}
}
}
consteval void PrintResultMismatch(const Result &lhs, const Result &rhs) {
PrintResultMismatchImpl(lhs.GetDescription(), rhs.GetDescription());
}
template<size_t Index, char Expected, char Actual>
struct PrintMismatchChar {
constexpr PrintMismatchChar() {
if (std::is_constant_evaluated()) {
__builtin_unreachable();
}
}
};
template<size_t Ix, char Expected, size_t C = 0>
consteval void PrintCharacterMismatch(char c) {
if (c == static_cast<char>(C)) {
PrintMismatchChar<Ix, Expected, static_cast<char>(C)>{};
return;
}
if constexpr (C < std::numeric_limits<unsigned char>::max()) {
PrintCharacterMismatch<Ix, Expected, C + 1>(c);
}
}
template<size_t Ix, char C = 0>
consteval void PrintCharacterMismatch(char c, char c2) {
if (c == static_cast<char>(C)) {
PrintCharacterMismatch<Ix, static_cast<char>(C)>(c2);
return;
}
if constexpr (C < std::numeric_limits<unsigned char>::max()) {
PrintCharacterMismatch<Ix, C + 1>(c, c2);
}
}
template<size_t Ix = 0>
consteval void PrintCharacterMismatch(size_t ix, char c, char c2) {
if (Ix == ix) {
PrintCharacterMismatch<Ix>(c, c2);
return;
}
if constexpr (Ix <= DefaultPathBufferSize) {
PrintCharacterMismatch<Ix + 1>(ix, c, c2);
}
}
#endif
consteval bool TestNormalizeImpl(const char *path, size_t buffer_size, const char *normalized, bool windows_path, bool drive_relative, bool all_chars, size_t expected_length, Result expected_result) {
/* Allocate a buffer to normalize into. */
char *buffer = new char[buffer_size];
ON_SCOPE_EXIT { delete[] buffer; };
buffer[buffer_size - 1] = '\xcc';
/* Perform normalization. */
size_t actual_length;
const Result actual_result = PathNormalizer::Normalize(buffer, std::addressof(actual_length), path, buffer_size, windows_path, drive_relative, all_chars);
/* Check that the expected result matches the actual. */
if (actual_result.GetValue() != expected_result.GetValue()) {
#if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING)
PrintResultMismatch(expected_result.GetValue(), actual_result.GetValue());
#endif
return false;
}
/* Check that the expected string matches the actual. */
for (size_t i = 0; i < buffer_size; ++i) {
if (normalized[i] != StringTraits::NullTerminator || R_SUCCEEDED(expected_result)) {
if (buffer[i] != normalized[i]) {
#if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING)
PrintCharacterMismatch(i, normalized[i], buffer[i]);
#endif
return false;
}
}
if (normalized[i] == StringTraits::NullTerminator || buffer[i] == StringTraits::NullTerminator) {
break;
}
}
/* Check that the expected length matches the actual. */
if (R_SUCCEEDED(expected_result) || fs::ResultTooLongPath::Includes(expected_result)) {
if (expected_length != actual_length) {
#if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING)
PrintResultMismatchImpl(static_cast<u32>(expected_length), static_cast<u32>(actual_length));
#endif
return false;
}
}
return true;
}
struct NormalizeTestData {
const char *path;
bool windows;
bool rel;
bool allow_all;
const char *normalized;
size_t len;
Result result;
};
template<size_t N, size_t Ix = 0>
consteval bool DoNormalizeTests(const NormalizeTestData (&tests)[N]) {
if constexpr (Ix >= N) {
return true;
}
const auto &test = tests[Ix];
if (!TestNormalizeImpl(test.path, DefaultPathBufferSize, test.normalized, test.windows, test.rel, test.allow_all, test.len, test.result)) {
return false;
}
if constexpr (Ix < N) {
return DoNormalizeTests<N, Ix + 1>(tests);
} else {
AMS_ASSUME(false);
}
}
consteval bool TestNormalized() {
constexpr NormalizeTestData Tests[] = {
{ "/aa/bb/c/", false, true, false, "/aa/bb/c", 8, ResultSuccess() },
{ "aa/bb/c/", false, false, false, "", 0, fs::ResultInvalidPathFormat() },
{ "aa/bb/c/", false, true, false, "/aa/bb/c", 8, ResultSuccess() },
{ "mount:a/b", false, true, false, "/", 0, fs::ResultInvalidCharacter() },
{ "mo|unt:a/b", false, true, true, "/mo|unt:a/b", 11, ResultSuccess() },
{ "/aa/bb/../..", true, false, false, "/", 1, ResultSuccess() },
{ "/aa/bb/../../..", true, false, false, "/", 1, ResultSuccess() },
{ "/aa/bb/../../..", false, false, false, "/aa/bb/", 0, fs::ResultDirectoryUnobtainable() },
{ "aa/bb/../../..", true, true, false, "/", 1, ResultSuccess() },
{ "aa/bb/../../..", false, true, false, "/aa/bb/", 0, fs::ResultDirectoryUnobtainable() },
{ "mount:a/b", false, true, true, "/mount:a/b", 10, ResultSuccess() },
{ "/a|/bb/cc", false, false, true, "/a|/bb/cc", 9, ResultSuccess() },
{ "/>a/bb/cc", false, false, true, "/>a/bb/cc", 9, ResultSuccess() },
{ "/aa/.</cc", false, false, true, "/aa/.</cc", 9, ResultSuccess() },
{ "/aa/..</cc", false, false, true, "/aa/..</cc", 10, ResultSuccess() },
{ "", false, false, false, "", 0, fs::ResultInvalidPathFormat() },
{ "/", false, false, false, "/", 1, ResultSuccess() },
{ "/.", false, false, false, "/", 1, ResultSuccess() },
{ "/./", false, false, false, "/", 1, ResultSuccess() },
{ "/..", false, false, false, "/", 0, fs::ResultDirectoryUnobtainable() },
{ "//.", false, false, false, "/", 1, ResultSuccess() },
{ "/ ..", false, false, false, "/ ..", 4, ResultSuccess() },
{ "/.. /", false, false, false, "/.. ", 4, ResultSuccess() },
{ "/. /.", false, false, false, "/. ", 3, ResultSuccess() },
{ "/aa/bb/cc/dd/./.././../..", false, false, false, "/aa", 3, ResultSuccess() },
{ "/aa/bb/cc/dd/./.././../../..", false, false, false, "/", 1, ResultSuccess() },
{ "/./aa/./bb/./cc/./dd/.", false, false, false, "/aa/bb/cc/dd", 12, ResultSuccess() },
{ "/aa\\bb/cc", false, false, false, "/aa\\bb/cc", 9, ResultSuccess() },
{ "/aa\\bb/cc", false, false, false, "/aa\\bb/cc", 9, ResultSuccess() },
{ "/a|/bb/cc", false, false, false, "/", 0, fs::ResultInvalidCharacter() },
{ "/>a/bb/cc", false, false, false, "/", 0, fs::ResultInvalidCharacter() },
{ "/aa/.</cc", false, false, false, "/aa/", 0, fs::ResultInvalidCharacter() },
{ "/aa/..</cc", false, false, false, "/aa/", 0, fs::ResultInvalidCharacter() },
{ "\\\\aa/bb/cc", false, false, false, "", 0, fs::ResultInvalidPathFormat() },
{ "\\\\aa\\bb\\cc", false, false, false, "", 0, fs::ResultInvalidPathFormat() },
{ "/aa/bb/..\\cc", false, false, false, "/aa/cc", 6, ResultSuccess() },
{ "/aa/bb\\..\\cc", false, false, false, "/aa/cc", 6, ResultSuccess() },
{ "/aa/bb\\..", false, false, false, "/aa", 3, ResultSuccess() },
{ "/aa\\bb/../cc", false, false, false, "/cc", 3, ResultSuccess() }
};
return DoNormalizeTests(Tests);
}
static_assert(TestNormalized());
struct NormalizeTestDataSmallBuffer {
const char *path;
size_t buffer_size;
const char *normalized;
size_t len;
Result result;
};
template<size_t N, size_t Ix = 0>
consteval bool DoNormalizeTests(const NormalizeTestDataSmallBuffer (&tests)[N]) {
if constexpr (Ix >= N) {
return true;
}
const auto &test = tests[Ix];
if (!TestNormalizeImpl(test.path, test.buffer_size, test.normalized, false, false, false, test.len, test.result)) {
return false;
}
if constexpr (Ix < N) {
return DoNormalizeTests<N, Ix + 1>(tests);
} else {
AMS_ASSUME(false);
}
}
consteval bool TestNormalizedSmallBuffer() {
constexpr NormalizeTestDataSmallBuffer Tests[] = {
{ "/aa/bb/cc/", 7, "/aa/bb", 6, fs::ResultTooLongPath() },
{ "/aa/bb/cc/", 8, "/aa/bb/", 7, fs::ResultTooLongPath() },
{ "/aa/bb/cc/", 9, "/aa/bb/c", 8, fs::ResultTooLongPath() },
{ "/aa/bb/cc/", 10, "/aa/bb/cc", 9, ResultSuccess() },
{ "/aa/bb/cc", 9, "/aa/bb/c", 8, fs::ResultTooLongPath() },
{ "/aa/bb/cc", 10, "/aa/bb/cc", 9, ResultSuccess() },
{ "/./aa/./bb/./cc", 9, "/aa/bb/c", 8, fs::ResultTooLongPath() },
{ "/./aa/./bb/./cc", 10, "/aa/bb/cc", 9, ResultSuccess() },
{ "/aa/bb/cc/../../..", 9, "/aa/bb/c", 8, fs::ResultTooLongPath() },
{ "/aa/bb/cc/../../..", 10, "/aa/bb/cc", 9, fs::ResultTooLongPath() },
{ "/aa/bb/.", 7, "/aa/bb", 6, fs::ResultTooLongPath() },
{ "/aa/bb/./", 7, "/aa/bb", 6, fs::ResultTooLongPath() },
{ "/aa/bb/..", 8, "/aa", 3, ResultSuccess() },
{ "/aa/bb", 1, "", 0, fs::ResultTooLongPath() },
{ "/aa/bb", 2, "/", 1, fs::ResultTooLongPath() },
{ "/aa/bb", 3, "/a", 2, fs::ResultTooLongPath() },
{ "aa/bb", 1, "", 0, fs::ResultInvalidPathFormat() }
};
return DoNormalizeTests(Tests);
}
static_assert(TestNormalizedSmallBuffer());
consteval bool TestIsNormalizedImpl(const char *path, bool allow_all, bool expected_normalized, size_t expected_size, Result expected_result) {
/* Perform normalization checking. */
bool actual_normalized;
size_t actual_size = 0;
const Result actual_result = PathNormalizer::IsNormalized(std::addressof(actual_normalized), std::addressof(actual_size), path, allow_all);
/* Check that the expected result matches the actual. */
if (actual_result.GetValue() != expected_result.GetValue()) {
#if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING)
PrintResultMismatch(expected_result.GetValue(), actual_result.GetValue());
#endif
return false;
}
if (expected_size != actual_size) {
#if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING)
PrintResultMismatchImpl(static_cast<u32>(expected_size), static_cast<u32>(actual_size));
#endif
return false;
}
/* Check that the expected output matches the actual. */
if (R_SUCCEEDED(expected_result)) {
if (expected_normalized != actual_normalized) {
#if defined(ENABLE_PRINT_FORMAT_TEST_DEBUGGING)
PrintResultMismatchImpl(static_cast<u32>(expected_normalized), static_cast<u32>(actual_normalized));
#endif
return false;
}
}
return true;
}
struct IsNormalizedTestData {
const char *path;
bool allow_all;
bool normalized;
size_t len;
Result result;
};
template<size_t N, size_t Ix = 0>
consteval bool DoIsNormalizedTests(const IsNormalizedTestData (&tests)[N]) {
if constexpr (Ix >= N) {
return true;
}
const auto &test = tests[Ix];
if (!TestIsNormalizedImpl(test.path, test.allow_all, test.normalized, test.len, test.result)) {
return false;
}
if constexpr (Ix < N) {
return DoIsNormalizedTests<N, Ix + 1>(tests);
} else {
AMS_ASSUME(false);
}
}
consteval bool TestIsNormalized() {
constexpr IsNormalizedTestData Tests[] = {
{ "/aa/bb/c/", false, false, 9, ResultSuccess() },
{ "aa/bb/c/", false, false, 0, fs::ResultInvalidPathFormat() },
{ "aa/bb/c/", false, false, 0, fs::ResultInvalidPathFormat() },
{ "mount:a/b", false, false, 0, fs::ResultInvalidPathFormat() },
{ "mo|unt:a/b", true, false, 0, fs::ResultInvalidPathFormat() },
{ "/aa/bb/../..", false, false, 0, ResultSuccess() },
{ "/aa/bb/../../..", false, false, 0, ResultSuccess() },
{ "/aa/bb/../../..", false, false, 0, ResultSuccess() },
{ "aa/bb/../../..", false, false, 0, fs::ResultInvalidPathFormat() },
{ "aa/bb/../../..", false, false, 0, fs::ResultInvalidPathFormat() },
{ "mount:a/b", true, false, 0, fs::ResultInvalidPathFormat() },
{ "/a|/bb/cc", true, true, 9, ResultSuccess() },
{ "/>a/bb/cc", true, true, 9, ResultSuccess() },
{ "/aa/.</cc", true, true, 9, ResultSuccess() },
{ "/aa/..</cc", true, true, 10, ResultSuccess() },
{ "", false, false, 0, fs::ResultInvalidPathFormat() },
{ "/", false, true, 1, ResultSuccess() },
{ "/.", false, false, 2, ResultSuccess() },
{ "/./", false, false, 0, ResultSuccess() },
{ "/..", false, false, 3, ResultSuccess() },
{ "//.", false, false, 0, ResultSuccess() },
{ "/ ..", false, true, 4, ResultSuccess() },
{ "/.. /", false, false, 5, ResultSuccess() },
{ "/. /.", false, false, 5, ResultSuccess() },
{ "/aa/bb/cc/dd/./.././../..", false, false, 0, ResultSuccess() },
{ "/aa/bb/cc/dd/./.././../../..", false, false, 0, ResultSuccess() },
{ "/./aa/./bb/./cc/./dd/.", false, false, 0, ResultSuccess() },
{ "/aa\\bb/cc", false, true, 9, ResultSuccess() },
{ "/aa\\bb/cc", false, true, 9, ResultSuccess() },
{ "/a|/bb/cc", false, false, 0, fs::ResultInvalidCharacter() },
{ "/>a/bb/cc", false, false, 0, fs::ResultInvalidCharacter() },
{ "/aa/.</cc", false, false, 0, fs::ResultInvalidCharacter() },
{ "/aa/..</cc", false, false, 0, fs::ResultInvalidCharacter() },
{ "\\\\aa/bb/cc", false, false, 0, fs::ResultInvalidPathFormat() },
{ "\\\\aa\\bb\\cc", false, false, 0, fs::ResultInvalidPathFormat() },
{ "/aa/bb/..\\cc", false, true, 12, ResultSuccess() },
{ "/aa/bb\\..\\cc", false, true, 12, ResultSuccess() },
{ "/aa/bb\\..", false, true, 9, ResultSuccess() },
{ "/aa\\bb/../cc", false, false, 0, ResultSuccess() }
};
return DoIsNormalizedTests(Tests);
}
static_assert(TestIsNormalized());
}
}

View File

@@ -1,73 +0,0 @@
/*
* Copyright (c) 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 <stratosphere.hpp>
namespace ams::fs {
namespace {
struct IsSubPathTestData {
const char *lhs;
const char *rhs;
bool is_sub_path;
};
template<size_t N, size_t Ix = 0>
consteval bool DoIsSubPathTests(const IsSubPathTestData (&tests)[N]) {
if constexpr (Ix >= N) {
return true;
}
const auto &test = tests[Ix];
if (::ams::fs::IsSubPath(test.lhs, test.rhs) != test.is_sub_path) {
return false;
}
if constexpr (Ix < N) {
return DoIsSubPathTests<N, Ix + 1>(tests);
} else {
AMS_ASSUME(false);
}
}
consteval bool TestIsSubPath() {
constexpr IsSubPathTestData Tests[] = {
{ "//a/b", "/a", false },
{ "/a", "//a/b", false },
{ "//a/b", "\\\\a", false },
{ "//a/b", "//a", true },
{ "/", "/a", true },
{ "/a", "/", true },
{ "/", "/", false },
{ "", "", false },
{ "/", "", true },
{ "/", "mount:/a", false },
{ "mount:/", "mount:/", false },
{ "mount:/a/b", "mount:/a/b", false },
{ "mount:/a/b", "mount:/a/b/c", true },
{ "/a/b", "/a/b/c", true },
{ "/a/b/c", "/a/b", true },
{ "/a/b", "/a/b", false },
{ "/a/b", "/a/b\\c", false }
};
return DoIsSubPathTests(Tests);
}
static_assert(TestIsSubPath());
}
}