Revert "hoc-clk: add live vdd2, live boost clock and basic pwm dimming"
This reverts commit 15b7df8ef1.
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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{})));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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); }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user