ams: support building unit test programs on windows/linux/macos

This commit is contained in:
Michael Scire
2022-03-06 12:08:20 -08:00
committed by SciresM
parent 9a38be201a
commit 64a97576d0
756 changed files with 33359 additions and 9372 deletions

View File

@@ -206,7 +206,7 @@ namespace ams::fssystem {
/* Setup the keyslot cache. */
for (s32 i = 0; i < KeySlotCacheEntryCount; i++) {
s32 slot_index;
s32 slot_index = -1;
R_ABORT_UNLESS(spl::AllocateAesKeySlot(std::addressof(slot_index)));
g_key_slot_cache_entry[i].emplace(slot_index);
g_key_slot_cache.AddEntry(std::addressof(g_key_slot_cache_entry[i].value()));

View File

@@ -1,129 +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::fssystem {
DirectoryRedirectionFileSystem::DirectoryRedirectionFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs, const char *before, const char *after, bool unc)
: PathResolutionFileSystem(fs, unc)
{
m_before_dir = nullptr;
m_after_dir = nullptr;
R_ABORT_UNLESS(this->Initialize(before, after));
}
DirectoryRedirectionFileSystem::DirectoryRedirectionFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs, const char *before, const char *after, bool unc)
: PathResolutionFileSystem(std::move(fs), unc)
{
m_before_dir = nullptr;
m_after_dir = nullptr;
R_ABORT_UNLESS(this->Initialize(before, after));
}
DirectoryRedirectionFileSystem::~DirectoryRedirectionFileSystem() {
if (m_before_dir != nullptr) {
fs::impl::Deallocate(m_before_dir, m_before_dir_len);
}
if (m_after_dir != nullptr) {
fs::impl::Deallocate(m_after_dir, m_after_dir_len);
}
}
Result DirectoryRedirectionFileSystem::GetNormalizedDirectoryPath(char **out, size_t *out_size, const char *dir) {
/* Clear output. */
*out = nullptr;
*out_size = 0;
/* Make sure the path isn't too long. */
R_UNLESS(strnlen(dir, fs::EntryNameLengthMax + 1) <= fs::EntryNameLengthMax, fs::ResultTooLongPath());
/* Normalize the path. */
char normalized_path[fs::EntryNameLengthMax + 2];
size_t normalized_path_len;
R_TRY(fs::PathNormalizer::Normalize(normalized_path, &normalized_path_len, dir, sizeof(normalized_path), this->IsUncPreserved(), false));
/* Ensure terminating '/' */
if (!fs::PathNormalizer::IsSeparator(normalized_path[normalized_path_len - 1])) {
AMS_ASSERT(normalized_path_len + 2 < sizeof(normalized_path));
normalized_path[normalized_path_len] = fs::StringTraits::DirectorySeparator;
normalized_path[normalized_path_len + 1] = fs::StringTraits::NullTerminator;
++normalized_path_len;
}
/* Allocate new path. */
const size_t size = normalized_path_len + 1;
char *new_dir = static_cast<char *>(fs::impl::Allocate(size));
AMS_ABORT_UNLESS(new_dir != nullptr);
/* TODO: custom fs::ResultAllocationFailure? */
/* Copy path in. */
std::memcpy(new_dir, normalized_path, normalized_path_len);
new_dir[normalized_path_len] = fs::StringTraits::NullTerminator;
/* Set output. */
*out = new_dir;
*out_size = size;
return ResultSuccess();
}
Result DirectoryRedirectionFileSystem::Initialize(const char *before, const char *after) {
/* Normalize both directories. */
this->GetNormalizedDirectoryPath(std::addressof(m_before_dir), std::addressof(m_before_dir_len), before);
this->GetNormalizedDirectoryPath(std::addressof(m_after_dir), std::addressof(m_after_dir_len), after);
return ResultSuccess();
}
Result DirectoryRedirectionFileSystem::ResolveFullPath(char *out, size_t out_size, const char *relative_path) {
/* Check pre-conditions. */
AMS_ASSERT(relative_path[0] == '/');
AMS_ASSERT(m_before_dir_len >= 2);
AMS_ASSERT(m_after_dir_len >= 2);
AMS_ASSERT(m_after_dir_len <= out_size);
AMS_ASSERT(fs::PathNormalizer::IsNullTerminator(m_before_dir[m_before_dir_len - 1]));
AMS_ASSERT(fs::PathNormalizer::IsSeparator(m_before_dir[m_before_dir_len - 2]));
AMS_ASSERT(fs::PathNormalizer::IsNullTerminator(m_after_dir[m_after_dir_len - 1]));
AMS_ASSERT(fs::PathNormalizer::IsSeparator(m_after_dir[m_after_dir_len - 2]));
/* Normalize the relative path. */
char normalized_rel_path[fs::EntryNameLengthMax + 1];
size_t normalized_rel_path_len;
R_TRY(fs::PathNormalizer::Normalize(normalized_rel_path, std::addressof(normalized_rel_path_len), relative_path, sizeof(normalized_rel_path), this->IsUncPreserved(), false));
const bool is_prefixed = std::memcmp(normalized_rel_path, m_before_dir, m_before_dir_len - 2) == 0 &&
(fs::PathNormalizer::IsSeparator(normalized_rel_path[m_before_dir_len - 2]) || fs::PathNormalizer::IsNullTerminator(normalized_rel_path[m_before_dir_len - 2]));
if (is_prefixed) {
const size_t before_prefix_len = m_before_dir_len - 2;
const size_t after_prefix_len = m_after_dir_len - 2;
const size_t final_str_len = after_prefix_len + normalized_rel_path_len - before_prefix_len;
R_UNLESS(final_str_len < out_size, fs::ResultTooLongPath());
/* Copy normalized path. */
std::memcpy(out, m_after_dir, after_prefix_len);
std::memcpy(out + after_prefix_len, normalized_rel_path + before_prefix_len, normalized_rel_path_len - before_prefix_len);
out[final_str_len] = fs::StringTraits::NullTerminator;
} else {
/* Path is not prefixed. */
R_UNLESS(normalized_rel_path_len + 1 <= out_size, fs::ResultTooLongPath());
std::memcpy(out, normalized_rel_path, normalized_rel_path_len);
out[normalized_rel_path_len] = fs::StringTraits::NullTerminator;
}
return ResultSuccess();
}
}

View File

@@ -19,13 +19,15 @@ namespace ams::fssystem {
namespace {
constexpr size_t IdealWorkBufferSize = 0x100000; /* 1 MiB */
constexpr size_t IdealWorkBufferSize = 1_MB;
constexpr size_t MinimumWorkBufferSize = 1_KB;
constexpr const char CommittedDirectoryPath[] = "/0/";
constexpr const char WorkingDirectoryPath[] = "/1/";
constexpr const char SynchronizingDirectoryPath[] = "/_/";
constexpr const fs::Path CommittedDirectoryPath = fs::MakeConstantPath("/0");
constexpr const fs::Path WorkingDirectoryPath = fs::MakeConstantPath("/1");
constexpr const fs::Path SynchronizingDirectoryPath = fs::MakeConstantPath("/_");
constexpr const fs::Path LockFilePath = fs::MakeConstantPath("/.lock");
class DirectorySaveDataFile : public fs::fsa::IFile {
class DirectorySaveDataFile : public fs::fsa::IFile, public fs::impl::Newable {
private:
std::unique_ptr<fs::fsa::IFile> m_base_file;
DirectorySaveDataFileSystem *m_parent_fs;
@@ -38,7 +40,7 @@ namespace ams::fssystem {
virtual ~DirectorySaveDataFile() {
/* Observe closing of writable file. */
if (m_open_mode & fs::OpenMode_Write) {
m_parent_fs->OnWritableFileClose();
m_parent_fs->DecrementWriteOpenFileCount();
}
}
public:
@@ -73,25 +75,14 @@ namespace ams::fssystem {
}
DirectorySaveDataFileSystem::DirectorySaveDataFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs)
: PathResolutionFileSystem(fs), m_accessor_mutex(), m_open_writable_files(0)
{
/* ... */
}
Result DirectorySaveDataFileSystem::Initialize(bool journaling_supported, bool multi_commit_supported, bool journaling_enabled) {
/* Configure ourselves. */
m_is_journaling_supported = journaling_supported;
m_is_multi_commit_supported = multi_commit_supported;
m_is_journaling_enabled = journaling_enabled;
DirectorySaveDataFileSystem::DirectorySaveDataFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs)
: PathResolutionFileSystem(std::move(fs)), m_accessor_mutex(), m_open_writable_files(0)
{
/* ... */
}
DirectorySaveDataFileSystem::~DirectorySaveDataFileSystem() {
/* ... */
}
Result DirectorySaveDataFileSystem::Initialize() {
/* Nintendo does not acquire the lock here, but I think we probably should. */
std::scoped_lock lk(m_accessor_mutex);
/* Ensure that we can initialize further by acquiring a lock on the filesystem. */
R_TRY(this->AcquireLockFile());
fs::DirectoryEntryType type;
@@ -100,44 +91,35 @@ namespace ams::fssystem {
/* If path isn't found, create working directory and committed directory. */
R_CATCH(fs::ResultPathNotFound) {
R_TRY(m_base_fs->CreateDirectory(WorkingDirectoryPath));
R_TRY(m_base_fs->CreateDirectory(CommittedDirectoryPath));
if (m_is_journaling_supported) {
R_TRY(m_base_fs->CreateDirectory(CommittedDirectoryPath));
}
}
} R_END_TRY_CATCH;
/* Now check for the committed directory. */
R_TRY_CATCH(m_base_fs->GetEntryType(std::addressof(type), CommittedDirectoryPath)) {
/* Committed doesn't exist, so synchronize and rename. */
R_CATCH(fs::ResultPathNotFound) {
R_TRY(this->SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath));
R_TRY(m_base_fs->RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath));
return ResultSuccess();
}
} R_END_TRY_CATCH;
/* If we support journaling, we need to set up the committed directory. */
if (m_is_journaling_supported) {
/* Now check for the committed directory. */
R_TRY_CATCH(m_base_fs->GetEntryType(std::addressof(type), CommittedDirectoryPath)) {
/* Committed doesn't exist, so synchronize and rename. */
R_CATCH(fs::ResultPathNotFound) {
R_TRY(this->SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath));
R_TRY(m_base_fs->RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath));
R_SUCCEED();
}
} R_END_TRY_CATCH;
/* The committed directory exists, so synchronize it to the working directory. */
return this->SynchronizeDirectory(WorkingDirectoryPath, CommittedDirectoryPath);
}
Result DirectorySaveDataFileSystem::AllocateWorkBuffer(std::unique_ptr<u8[]> *out, size_t *out_size, size_t size) {
/* Repeatedly try to allocate until success. */
while (size > 0x200) {
/* Allocate the buffer. */
if (auto mem = new (std::nothrow) u8[size]; mem != nullptr) {
out->reset(mem);
*out_size = size;
return ResultSuccess();
} else {
/* Divide size by two. */
size >>= 1;
/* The committed directory exists, so if we should, synchronize it to the working directory. */
if (m_is_journaling_enabled) {
R_TRY(this->SynchronizeDirectory(WorkingDirectoryPath, CommittedDirectoryPath));
}
}
/* TODO: Return a result here? Nintendo does not, but they have other allocation failed results. */
/* Consider returning fs::ResultFsAllocationFailureInDirectorySaveDataFileSystem? */
AMS_ABORT_UNLESS(false);
R_SUCCEED();
}
Result DirectorySaveDataFileSystem::SynchronizeDirectory(const char *dst, const char *src) {
Result DirectorySaveDataFileSystem::SynchronizeDirectory(const fs::Path &dst, const fs::Path &src) {
/* Delete destination dir and recreate it. */
R_TRY_CATCH(m_base_fs->DeleteDirectoryRecursively(dst)) {
R_CATCH(fs::ResultPathNotFound) { /* Nintendo returns error unconditionally, but I think that's a bug in their code. */}
@@ -146,132 +128,239 @@ namespace ams::fssystem {
R_TRY(m_base_fs->CreateDirectory(dst));
/* Get a work buffer to work with. */
std::unique_ptr<u8[]> work_buf;
size_t work_buf_size;
R_TRY(this->AllocateWorkBuffer(std::addressof(work_buf), std::addressof(work_buf_size), IdealWorkBufferSize));
fssystem::PooledBuffer buffer;
buffer.AllocateParticularlyLarge(IdealWorkBufferSize, MinimumWorkBufferSize);
/* Copy the directory recursively. */
return fssystem::CopyDirectoryRecursively(m_base_fs, dst, src, work_buf.get(), work_buf_size);
fs::DirectoryEntry dir_entry_buffer = {};
R_RETURN(fssystem::CopyDirectoryRecursively(m_base_fs, dst, src, std::addressof(dir_entry_buffer), buffer.GetBuffer(), buffer.GetSize()));
}
Result DirectorySaveDataFileSystem::ResolveFullPath(char *out, size_t out_size, const char *relative_path) {
R_UNLESS(strnlen(relative_path, fs::EntryNameLengthMax + 1) < fs::EntryNameLengthMax + 1, fs::ResultTooLongPath());
R_UNLESS(fs::PathNormalizer::IsSeparator(relative_path[0]), fs::ResultInvalidPath());
/* Copy working directory path. */
std::strncpy(out, WorkingDirectoryPath, out_size);
out[out_size - 1] = fs::StringTraits::NullTerminator;
/* Normalize it. */
constexpr size_t WorkingDirectoryPathLength = sizeof(WorkingDirectoryPath) - 1;
size_t normalized_length;
return fs::PathNormalizer::Normalize(out + WorkingDirectoryPathLength - 1, std::addressof(normalized_length), relative_path, out_size - (WorkingDirectoryPathLength - 1));
Result DirectorySaveDataFileSystem::ResolvePath(fs::Path *out, const fs::Path &path) {
const fs::Path &directory = (m_is_journaling_supported && !m_is_journaling_enabled) ? CommittedDirectoryPath : WorkingDirectoryPath;
R_RETURN(out->Combine(directory, path));
}
void DirectorySaveDataFileSystem::OnWritableFileClose() {
Result DirectorySaveDataFileSystem::AcquireLockFile() {
/* If we already have a lock file, we don't need to lock again. */
R_SUCCEED_IF(m_lock_file != nullptr);
/* Open the lock file. */
std::unique_ptr<fs::fsa::IFile> file;
R_TRY_CATCH(m_base_fs->OpenFile(std::addressof(file), LockFilePath, fs::OpenMode_ReadWrite)) {
/* If the lock file doesn't yet exist, we may need to create it. */
R_CATCH(fs::ResultPathNotFound) {
R_TRY(m_base_fs->CreateFile(LockFilePath, 0));
R_TRY(m_base_fs->OpenFile(std::addressof(file), LockFilePath, fs::OpenMode_ReadWrite));
}
} R_END_TRY_CATCH;
/* Set our lock file. */
m_lock_file = std::move(file);
R_SUCCEED();
}
void DirectorySaveDataFileSystem::DecrementWriteOpenFileCount() {
std::scoped_lock lk(m_accessor_mutex);
m_open_writable_files--;
/* Nintendo does not check this, but I think it's sensible to do so. */
AMS_ABORT_UNLESS(m_open_writable_files >= 0);
--m_open_writable_files;
}
Result DirectorySaveDataFileSystem::CopySaveFromFileSystem(fs::fsa::IFileSystem *save_fs) {
/* If the input save is null, there's nothing to copy. */
R_SUCCEED_IF(save_fs == nullptr);
/* Get a work buffer to work with. */
std::unique_ptr<u8[]> work_buf;
size_t work_buf_size;
R_TRY(this->AllocateWorkBuffer(std::addressof(work_buf), std::addressof(work_buf_size), IdealWorkBufferSize));
/* Copy the directory recursively. */
R_TRY(fssystem::CopyDirectoryRecursively(m_base_fs, save_fs, fs::PathNormalizer::RootPath, fs::PathNormalizer::RootPath, work_buf.get(), work_buf_size));
return this->Commit();
}
/* Overridden from IPathResolutionFileSystem */
Result DirectorySaveDataFileSystem::DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(this->ResolveFullPath(full_path, sizeof(full_path), path));
Result DirectorySaveDataFileSystem::DoCreateFile(const fs::Path &path, s64 size, int option) {
/* Resolve the final path. */
fs::Path resolved;
R_TRY(this->ResolvePath(std::addressof(resolved), path));
/* Lock ourselves. */
std::scoped_lock lk(m_accessor_mutex);
R_RETURN(m_base_fs->CreateFile(resolved, size, option));
}
Result DirectorySaveDataFileSystem::DoDeleteFile(const fs::Path &path) {
/* Resolve the final path. */
fs::Path resolved;
R_TRY(this->ResolvePath(std::addressof(resolved), path));
/* Lock ourselves. */
std::scoped_lock lk(m_accessor_mutex);
R_RETURN(m_base_fs->DeleteFile(resolved));
}
Result DirectorySaveDataFileSystem::DoCreateDirectory(const fs::Path &path) {
/* Resolve the final path. */
fs::Path resolved;
R_TRY(this->ResolvePath(std::addressof(resolved), path));
/* Lock ourselves. */
std::scoped_lock lk(m_accessor_mutex);
R_RETURN(m_base_fs->CreateDirectory(resolved));
}
Result DirectorySaveDataFileSystem::DoDeleteDirectory(const fs::Path &path) {
/* Resolve the final path. */
fs::Path resolved;
R_TRY(this->ResolvePath(std::addressof(resolved), path));
/* Lock ourselves. */
std::scoped_lock lk(m_accessor_mutex);
R_RETURN(m_base_fs->DeleteDirectory(resolved));
}
Result DirectorySaveDataFileSystem::DoDeleteDirectoryRecursively(const fs::Path &path) {
/* Resolve the final path. */
fs::Path resolved;
R_TRY(this->ResolvePath(std::addressof(resolved), path));
/* Lock ourselves. */
std::scoped_lock lk(m_accessor_mutex);
R_RETURN(m_base_fs->DeleteDirectoryRecursively(resolved));
}
Result DirectorySaveDataFileSystem::DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) {
/* Resolve the final paths. */
fs::Path old_resolved;
fs::Path new_resolved;
R_TRY(this->ResolvePath(std::addressof(old_resolved), old_path));
R_TRY(this->ResolvePath(std::addressof(new_resolved), new_path));
/* Lock ourselves. */
std::scoped_lock lk(m_accessor_mutex);
R_RETURN(m_base_fs->RenameFile(old_resolved, new_resolved));
}
Result DirectorySaveDataFileSystem::DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) {
/* Resolve the final paths. */
fs::Path old_resolved;
fs::Path new_resolved;
R_TRY(this->ResolvePath(std::addressof(old_resolved), old_path));
R_TRY(this->ResolvePath(std::addressof(new_resolved), new_path));
/* Lock ourselves. */
std::scoped_lock lk(m_accessor_mutex);
R_RETURN(m_base_fs->RenameDirectory(old_resolved, new_resolved));
}
Result DirectorySaveDataFileSystem::DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) {
/* Resolve the final path. */
fs::Path resolved;
R_TRY(this->ResolvePath(std::addressof(resolved), path));
/* Lock ourselves. */
std::scoped_lock lk(m_accessor_mutex);
R_RETURN(m_base_fs->GetEntryType(out, resolved));
}
Result DirectorySaveDataFileSystem::DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) {
/* Resolve the final path. */
fs::Path resolved;
R_TRY(this->ResolvePath(std::addressof(resolved), path));
/* Lock ourselves. */
std::scoped_lock lk(m_accessor_mutex);
/* Open base file. */
std::unique_ptr<fs::fsa::IFile> base_file;
R_TRY(m_base_fs->OpenFile(std::addressof(base_file), full_path, mode));
R_TRY(m_base_fs->OpenFile(std::addressof(base_file), resolved, mode));
std::unique_ptr<DirectorySaveDataFile> file(new (std::nothrow) DirectorySaveDataFile(std::move(base_file), this, mode));
/* Make DirectorySaveDataFile. */
std::unique_ptr<fs::fsa::IFile> file = std::make_unique<DirectorySaveDataFile>(std::move(base_file), this, mode);
R_UNLESS(file != nullptr, fs::ResultAllocationFailureInDirectorySaveDataFileSystem());
/* Increment our open writable files, if the file is writable. */
if (mode & fs::OpenMode_Write) {
m_open_writable_files++;
++m_open_writable_files;
}
/* Set the output. */
*out_file = std::move(file);
return ResultSuccess();
R_SUCCEED();
}
Result DirectorySaveDataFileSystem::DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) {
/* Resolve the final path. */
fs::Path resolved;
R_TRY(this->ResolvePath(std::addressof(resolved), path));
/* Lock ourselves. */
std::scoped_lock lk(m_accessor_mutex);
R_RETURN(m_base_fs->OpenDirectory(out_dir, resolved, mode));
}
Result DirectorySaveDataFileSystem::DoCommit() {
/* Here, Nintendo does the following (with retries): */
/* - Rename Committed -> Synchronizing. */
/* - Synchronize Working -> Synchronizing (deleting Synchronizing). */
/* - Rename Synchronizing -> Committed. */
/* Lock ourselves. */
std::scoped_lock lk(m_accessor_mutex);
R_UNLESS(m_open_writable_files == 0, fs::ResultPreconditionViolation());
/* If we aren't journaling, we don't need to do anything. */
R_SUCCEED_IF(!m_is_journaling_enabled);
R_SUCCEED_IF(!m_is_journaling_supported);
const auto RenameCommitedDir = [&]() { return m_base_fs->RenameDirectory(CommittedDirectoryPath, SynchronizingDirectoryPath); };
const auto SynchronizeWorkingDir = [&]() { return this->SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath); };
const auto RenameSynchronizingDir = [&]() { return m_base_fs->RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath); };
/* Check that there are no open files blocking the commit. */
R_UNLESS(m_open_writable_files == 0, fs::ResultWriteModeFileNotClosed());
/* Rename Committed -> Synchronizing. */
R_TRY(fssystem::RetryFinitelyForTargetLocked(std::move(RenameCommitedDir)));
/* Remove the previous commit by renaming the folder. */
R_TRY(fssystem::RetryFinitelyForTargetLocked([&] () ALWAYS_INLINE_LAMBDA { R_RETURN(m_base_fs->RenameDirectory(CommittedDirectoryPath, SynchronizingDirectoryPath)); }));
/* - Synchronize Working -> Synchronizing (deleting Synchronizing). */
R_TRY(fssystem::RetryFinitelyForTargetLocked(std::move(SynchronizeWorkingDir)));
/* Synchronize the working directory to the synchronizing directory. */
R_TRY(fssystem::RetryFinitelyForTargetLocked([&] () ALWAYS_INLINE_LAMBDA { R_RETURN(this->SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath)); }));
/* - Rename Synchronizing -> Committed. */
R_TRY(fssystem::RetryFinitelyForTargetLocked(std::move(RenameSynchronizingDir)));
/* Rename the synchronized directory to commit it. */
R_TRY(fssystem::RetryFinitelyForTargetLocked([&] () ALWAYS_INLINE_LAMBDA { R_RETURN(m_base_fs->RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath)); }));
/* TODO: Should I call m_base_fs->Commit()? Nintendo does not. */
return ResultSuccess();
R_SUCCEED();
}
Result DirectorySaveDataFileSystem::DoGetFreeSpaceSize(s64 *out, const fs::Path &path) {
/* Lock ourselves. */
std::scoped_lock lk(m_accessor_mutex);
/* Get the free space size in our working directory. */
AMS_UNUSED(path);
R_RETURN(m_base_fs->GetFreeSpaceSize(out, WorkingDirectoryPath));
}
Result DirectorySaveDataFileSystem::DoGetTotalSpaceSize(s64 *out, const fs::Path &path) {
/* Lock ourselves. */
std::scoped_lock lk(m_accessor_mutex);
/* Get the free space size in our working directory. */
AMS_UNUSED(path);
R_RETURN(m_base_fs->GetTotalSpaceSize(out, WorkingDirectoryPath));
}
Result DirectorySaveDataFileSystem::DoCleanDirectoryRecursively(const fs::Path &path) {
/* Resolve the final path. */
fs::Path resolved;
R_TRY(this->ResolvePath(std::addressof(resolved), path));
/* Lock ourselves. */
std::scoped_lock lk(m_accessor_mutex);
R_RETURN(m_base_fs->CleanDirectoryRecursively(resolved));
}
/* Overridden from IPathResolutionFileSystem but not commands. */
Result DirectorySaveDataFileSystem::DoCommitProvisionally(s64 counter) {
/* Nintendo does nothing here. */
/* Check that we support multi-commit. */
R_UNLESS(m_is_multi_commit_supported, fs::ResultUnsupportedOperationInDirectorySaveDataFileSystemA());
/* Do nothing. */
AMS_UNUSED(counter);
return ResultSuccess();
R_SUCCEED();
}
Result DirectorySaveDataFileSystem::DoRollback() {
/* Initialize overwrites the working directory with the committed directory. */
return this->Initialize();
}
/* On non-journaled savedata, there's nothing to roll back to. */
R_SUCCEED_IF(!m_is_journaling_supported);
/* Explicitly overridden to be not implemented. */
Result DirectorySaveDataFileSystem::DoGetFreeSpaceSize(s64 *out, const char *path) {
AMS_UNUSED(out, path);
return fs::ResultNotImplemented();
}
Result DirectorySaveDataFileSystem::DoGetTotalSpaceSize(s64 *out, const char *path) {
AMS_UNUSED(out, path);
return fs::ResultNotImplemented();
}
Result DirectorySaveDataFileSystem::DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const char *path) {
AMS_UNUSED(out, path);
return fs::ResultNotImplemented();
}
Result DirectorySaveDataFileSystem::DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) {
AMS_UNUSED(dst, dst_size, src, src_size, query, path);
return fs::ResultNotImplemented();
}
Result DirectorySaveDataFileSystem::DoFlush() {
return fs::ResultNotImplemented();
/* Perform a re-initialize. */
R_RETURN(this->Initialize(m_is_journaling_supported, m_is_multi_commit_supported, m_is_journaling_enabled));
}
}

View File

@@ -17,6 +17,7 @@
namespace ams::fssystem {
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
namespace {
constexpr inline size_t MaxExternalCodeFileSystem = 0x10;
@@ -72,5 +73,21 @@ namespace ams::fssystem {
g_hnd_map.Remove(program_id);
}
}
#else
fs::fsa::IFileSystem *GetExternalCodeFileSystem(ncm::ProgramId program_id) {
AMS_UNUSED(program_id);
return nullptr;
}
Result CreateExternalCode(os::NativeHandle *out, ncm::ProgramId program_id) {
AMS_UNUSED(out, program_id);
R_THROW(fs::ResultNotImplemented());
}
void DestroyExternalCode(ncm::ProgramId program_id) {
AMS_UNUSED(program_id);
}
#endif
}

View File

@@ -39,9 +39,9 @@ namespace ams::fssystem {
constexpr size_t MaxCacheCount = 1024;
constexpr size_t BlockSize = 16_KB;
alignas(os::MemoryPageSize) u8 g_exp_heap_buffer[ExpHeapSize];
lmem::HeapHandle g_exp_heap_handle = nullptr;
fssrv::PeakCheckableMemoryResourceFromExpHeap g_exp_allocator(ExpHeapSize);
alignas(os::MemoryPageSize) constinit u8 g_exp_heap_buffer[ExpHeapSize];
constinit lmem::HeapHandle g_exp_heap_handle = nullptr;
constinit fssrv::PeakCheckableMemoryResourceFromExpHeap g_exp_allocator(ExpHeapSize);
void InitializeExpHeap() {
if (g_exp_heap_handle == nullptr) {
@@ -70,25 +70,25 @@ namespace ams::fssystem {
lmem::FreeToExpHeap(g_exp_heap_handle, p);
}
alignas(os::MemoryPageSize) u8 g_device_buffer[DeviceBufferSize];
alignas(os::MemoryPageSize) constinit u8 g_device_buffer[DeviceBufferSize] = {};
alignas(os::MemoryPageSize) u8 g_buffer_pool[BufferPoolSize];
alignas(os::MemoryPageSize) constinit u8 g_buffer_pool[BufferPoolSize] = {};
util::TypedStorage<mem::StandardAllocator> g_buffer_allocator;
util::TypedStorage<fssrv::MemoryResourceFromStandardAllocator> g_allocator;
constinit util::TypedStorage<mem::StandardAllocator> g_buffer_allocator = {};
constinit util::TypedStorage<fssrv::MemoryResourceFromStandardAllocator> g_allocator = {};
/* TODO: Nintendo uses os::SetMemoryHeapSize (svc::SetHeapSize) and os::AllocateMemoryBlock for the BufferManager heap. */
/* It's unclear how we should handle this in ams.mitm (especially hoping to reuse some logic for fs reimpl). */
/* Should we be doing the same(?) */
util::TypedStorage<fssystem::FileSystemBufferManager> g_buffer_manager;
alignas(os::MemoryPageSize) u8 g_buffer_manager_heap[BufferManagerHeapSize];
constinit util::TypedStorage<fssystem::FileSystemBufferManager> g_buffer_manager = {};
alignas(os::MemoryPageSize) constinit u8 g_buffer_manager_heap[BufferManagerHeapSize] = {};
/* FileSystem creators. */
util::TypedStorage<fssrv::fscreator::RomFileSystemCreator> g_rom_fs_creator;
util::TypedStorage<fssrv::fscreator::PartitionFileSystemCreator> g_partition_fs_creator;
util::TypedStorage<fssrv::fscreator::StorageOnNcaCreator> g_storage_on_nca_creator;
constinit util::TypedStorage<fssrv::fscreator::RomFileSystemCreator> g_rom_fs_creator = {};
constinit util::TypedStorage<fssrv::fscreator::PartitionFileSystemCreator> g_partition_fs_creator = {};
constinit util::TypedStorage<fssrv::fscreator::StorageOnNcaCreator> g_storage_on_nca_creator = {};
fssrv::fscreator::FileSystemCreatorInterfaces g_fs_creator_interfaces = {};
constinit fssrv::fscreator::FileSystemCreatorInterfaces g_fs_creator_interfaces = {};
}
@@ -162,7 +162,21 @@ namespace ams::fssystem {
/* TODO FS-REIMPL: Sd Card detection, speed emulation. */
/* Initialize fssrv. TODO FS-REIMPL: More arguments, more actions taken. */
fssrv::InitializeForFileSystemProxy(std::addressof(g_fs_creator_interfaces), GetPointer(g_buffer_manager), is_development_function_enabled);
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 = std::addressof(program_registry_service),
.m_access_log_service_impl = nullptr /* TODO */,
.m_debug_configuration_service_impl = nullptr /* TODO */,
};
fssrv::InitializeForFileSystemProxy(config);
/* TODO FS-REIMPL: GetFileSystemProxyServiceObject(), set current process, initialize global service object. */
@@ -241,7 +255,21 @@ namespace ams::fssystem {
};
/* Initialize fssrv. TODO FS-REIMPL: More arguments, more actions taken. */
fssrv::InitializeForFileSystemProxy(std::addressof(g_fs_creator_interfaces), GetPointer(g_buffer_manager), is_development_function_enabled);
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);
/* Disable auto-abort in fs library code. */
fs::SetEnabledAutoAbort(false);

File diff suppressed because it is too large Load Diff

View File

@@ -292,13 +292,13 @@ namespace ams::fssystem {
using IntegrityLevelInfo = NcaFsHeader::HashData::IntegrityMetaInfo::LevelHashInfo;
using IntegrityDataInfo = IntegrityLevelInfo::HierarchicalIntegrityVerificationLevelInformation;
inline const Sha256DataRegion &GetSha256DataRegion(const NcaFsHeader::HashData &hash_data) {
return hash_data.hierarchical_sha256_data.hash_layer_region[1];
}
// inline const Sha256DataRegion &GetSha256DataRegion(const NcaFsHeader::HashData &hash_data) {
// return hash_data.hierarchical_sha256_data.hash_layer_region[1];
// }
inline const IntegrityDataInfo &GetIntegrityDataInfo(const NcaFsHeader::HashData &hash_data) {
return hash_data.integrity_meta_info.level_hash_info.info[hash_data.integrity_meta_info.level_hash_info.max_layers - 2];
}
// inline const IntegrityDataInfo &GetIntegrityDataInfo(const NcaFsHeader::HashData &hash_data) {
// return hash_data.integrity_meta_info.level_hash_info.info[hash_data.integrity_meta_info.level_hash_info.max_layers - 2];
// }
}
@@ -706,7 +706,7 @@ namespace ams::fssystem {
Result NcaFileSystemDriver::CreateSparseStorage(std::shared_ptr<fs::IStorage> *out, s64 *out_fs_data_offset, std::shared_ptr<fssystem::SparseStorage> *out_sparse_storage, std::shared_ptr<fs::IStorage> *out_meta_storage, s32 index, const NcaAesCtrUpperIv &upper_iv, const NcaSparseInfo &sparse_info) {
/* Validate preconditions. */
AMS_ASSERT(out != nullptr);
AMS_ASSERT(base_storage != nullptr);
AMS_ASSERT(out_fs_data_offset != nullptr);
/* Check the sparse info generation. */
R_UNLESS(sparse_info.generation != 0, fs::ResultInvalidNcaHeader());

View File

@@ -375,7 +375,7 @@ namespace ams::fssystem {
/* Generate the hash. */
Hash hash;
crypto::GenerateSha256Hash(std::addressof(hash), sizeof(hash), std::addressof(m_data), sizeof(NcaFsHeader));
crypto::GenerateSha256(std::addressof(hash), sizeof(hash), std::addressof(m_data), sizeof(NcaFsHeader));
/* Validate the hash. */
R_UNLESS(crypto::IsSameBytes(std::addressof(reader.GetFsHeaderHash(index)), std::addressof(hash), sizeof(Hash)), fs::ResultNcaFsHeaderHashVerificationFailed());

View File

@@ -19,6 +19,8 @@ namespace ams::fssystem {
namespace {
constexpr const char RootPath[] = "/";
class PartitionFileSystemDefaultAllocator : public MemoryResource {
private:
virtual void *AllocateImpl(size_t size, size_t alignment) override {
@@ -53,7 +55,7 @@ namespace ams::fssystem {
virtual Result DoGetSize(s64 *out) override final {
*out = m_partition_entry->size;
return ResultSuccess();
R_SUCCEED();
}
virtual Result DoFlush() override final {
@@ -61,7 +63,7 @@ namespace ams::fssystem {
R_SUCCEED_IF((m_mode & fs::OpenMode_Write) == 0);
/* Flush base storage. */
return m_parent->m_base_storage->Flush();
R_RETURN(m_parent->m_base_storage->Flush());
}
virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final {
@@ -78,12 +80,12 @@ namespace ams::fssystem {
R_UNLESS(static_cast<s64>(offset + size) <= static_cast<s64>(m_partition_entry->size), fs::ResultInvalidSize());
/* Write to the base storage. */
return m_parent->m_base_storage->Write(m_parent->m_meta_data_size + m_partition_entry->offset + offset, buffer, size);
R_RETURN(m_parent->m_base_storage->Write(m_parent->m_meta_data_size + m_partition_entry->offset + offset, buffer, size));
}
virtual Result DoSetSize(s64 size) override final {
R_TRY(this->DrySetSize(size, m_mode));
return fs::ResultUnsupportedOperationInPartitionFileA();
R_RETURN(fs::ResultUnsupportedOperationInPartitionFileA());
}
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 {
@@ -96,7 +98,7 @@ namespace ams::fssystem {
case fs::OperationId::QueryRange:
break;
default:
return fs::ResultUnsupportedOperationInPartitionFileB();
R_THROW(fs::ResultUnsupportedOperationInPartitionFileB());
}
/* Validate offset and size. */
@@ -105,7 +107,7 @@ namespace ams::fssystem {
R_UNLESS(static_cast<s64>(offset + size) <= static_cast<s64>(m_partition_entry->size), fs::ResultInvalidSize());
R_UNLESS(static_cast<s64>(offset + size) >= offset, fs::ResultInvalidSize());
return m_parent->m_base_storage->OperateRange(dst, dst_size, op_id, m_parent->m_meta_data_size + m_partition_entry->offset + offset, size, src, src_size);
R_RETURN(m_parent->m_base_storage->OperateRange(dst, dst_size, op_id, m_parent->m_meta_data_size + m_partition_entry->offset + offset, size, src, src_size));
}
public:
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override {
@@ -125,7 +127,7 @@ namespace ams::fssystem {
/* Set output size. */
*out = read_size;
return ResultSuccess();
R_SUCCEED();
}
template<>
@@ -213,7 +215,7 @@ namespace ams::fssystem {
/* Set output size. */
*out = read_size;
return ResultSuccess();
R_SUCCEED();
}
template <typename MetaType>
@@ -229,7 +231,7 @@ namespace ams::fssystem {
/* There are no subdirectories. */
if ((m_mode & fs::OpenDirectoryMode_File) == 0) {
*out_count = 0;
return ResultSuccess();
R_SUCCEED();
}
/* Calculate number of entries. */
@@ -247,7 +249,7 @@ namespace ams::fssystem {
}
*out_count = entry_count;
return ResultSuccess();
R_SUCCEED();
}
virtual Result DoGetEntryCount(s64 *out) override final {
@@ -258,7 +260,7 @@ namespace ams::fssystem {
*out = 0;
}
return ResultSuccess();
R_SUCCEED();
}
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override {
@@ -294,13 +296,13 @@ namespace ams::fssystem {
m_base_storage = base_storage;
m_meta_data_size = m_meta_data->GetMetaDataSize();
m_initialized = true;
return ResultSuccess();
R_SUCCEED();
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::Initialize(std::unique_ptr<MetaType> &&meta_data, std::shared_ptr<fs::IStorage> base_storage) {
m_unique_meta_data = std::move(meta_data);
return this->Initialize(m_unique_meta_data.get(), base_storage);
R_RETURN(this->Initialize(m_unique_meta_data.get(), base_storage));
}
template <typename MetaType>
@@ -314,24 +316,24 @@ namespace ams::fssystem {
m_meta_data = meta_data;
m_meta_data_size = m_meta_data->GetMetaDataSize();
m_initialized = true;
return ResultSuccess();
R_SUCCEED();
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::Initialize(fs::IStorage *base_storage) {
return this->Initialize(base_storage, std::addressof(g_partition_filesystem_default_allocator));
R_RETURN(this->Initialize(base_storage, std::addressof(g_partition_filesystem_default_allocator)));
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::Initialize(std::shared_ptr<fs::IStorage> base_storage) {
m_shared_storage = std::move(base_storage);
return this->Initialize(m_shared_storage.get());
R_RETURN(this->Initialize(m_shared_storage.get()));
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::Initialize(std::shared_ptr<fs::IStorage> base_storage, MemoryResource *allocator) {
m_shared_storage = std::move(base_storage);
return this->Initialize(m_shared_storage.get(), allocator);
R_RETURN(this->Initialize(m_shared_storage.get(), allocator));
}
template <typename MetaType>
@@ -345,114 +347,116 @@ namespace ams::fssystem {
/* Output offset. */
*out_offset = m_meta_data_size + m_meta_data->GetEntry(entry_index)->offset;
return ResultSuccess();
R_SUCCEED();
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::DoGetEntryType(fs::DirectoryEntryType *out, const char *path) {
Result PartitionFileSystemCore<MetaType>::DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) {
/* Validate preconditions. */
R_UNLESS(m_initialized, fs::ResultPreconditionViolation());
R_UNLESS(fs::PathNormalizer::IsSeparator(path[0]), fs::ResultInvalidPathFormat());
const char * const p = path.GetString();
R_UNLESS(p[0] == RootPath[0], fs::ResultInvalidPathFormat());
/* Check if the path is for a directory. */
if (std::strncmp(path, fs::PathNormalizer::RootPath, sizeof(fs::PathNormalizer::RootPath)) == 0) {
if (util::Strncmp(p, RootPath, sizeof(RootPath))) {
*out = fs::DirectoryEntryType_Directory;
return ResultSuccess();
R_SUCCEED();
}
/* Ensure that path is for a file. */
R_UNLESS(m_meta_data->GetEntryIndex(path + 1) >= 0, fs::ResultPathNotFound());
R_UNLESS(m_meta_data->GetEntryIndex(p + 1) >= 0, fs::ResultPathNotFound());
*out = fs::DirectoryEntryType_File;
return ResultSuccess();
R_SUCCEED();
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) {
Result PartitionFileSystemCore<MetaType>::DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) {
/* Validate preconditions. */
R_UNLESS(m_initialized, fs::ResultPreconditionViolation());
/* Obtain and validate the entry index. */
const s32 entry_index = m_meta_data->GetEntryIndex(path + 1);
const s32 entry_index = m_meta_data->GetEntryIndex(path.GetString() + 1);
R_UNLESS(entry_index >= 0, fs::ResultPathNotFound());
/* Create and output the file directory. */
std::unique_ptr file = std::make_unique<PartitionFile>(this, m_meta_data->GetEntry(entry_index), mode);
R_UNLESS(file != nullptr, fs::ResultAllocationFailureInPartitionFileSystemB());
*out_file = std::move(file);
return ResultSuccess();
R_SUCCEED();
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) {
Result PartitionFileSystemCore<MetaType>::DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) {
/* Validate preconditions. */
R_UNLESS(m_initialized, fs::ResultPreconditionViolation());
R_UNLESS(std::strncmp(path, fs::PathNormalizer::RootPath, sizeof(fs::PathNormalizer::RootPath)) == 0, fs::ResultPathNotFound());
R_UNLESS(m_initialized, fs::ResultPreconditionViolation());
R_UNLESS(path == RootPath, fs::ResultPathNotFound());
/* Create and output the partition directory. */
std::unique_ptr directory = std::make_unique<PartitionDirectory>(this, mode);
R_UNLESS(directory != nullptr, fs::ResultAllocationFailureInPartitionFileSystemC());
*out_dir = std::move(directory);
return ResultSuccess();
R_SUCCEED();
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::DoCommit() {
return ResultSuccess();
R_SUCCEED();
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::DoCleanDirectoryRecursively(const char *path) {
Result PartitionFileSystemCore<MetaType>::DoCleanDirectoryRecursively(const fs::Path &path) {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInPartitionFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA());
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::DoCreateDirectory(const char *path) {
Result PartitionFileSystemCore<MetaType>::DoCreateDirectory(const fs::Path &path) {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInPartitionFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA());
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::DoCreateFile(const char *path, s64 size, int option) {
Result PartitionFileSystemCore<MetaType>::DoCreateFile(const fs::Path &path, s64 size, int option) {
AMS_UNUSED(path, size, option);
return fs::ResultUnsupportedOperationInPartitionFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA());
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::DoDeleteDirectory(const char *path) {
Result PartitionFileSystemCore<MetaType>::DoDeleteDirectory(const fs::Path &path) {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInPartitionFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA());
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::DoDeleteDirectoryRecursively(const char *path) {
Result PartitionFileSystemCore<MetaType>::DoDeleteDirectoryRecursively(const fs::Path &path) {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInPartitionFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA());
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::DoDeleteFile(const char *path) {
Result PartitionFileSystemCore<MetaType>::DoDeleteFile(const fs::Path &path) {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInPartitionFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA());
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::DoRenameDirectory(const char *old_path, const char *new_path) {
Result PartitionFileSystemCore<MetaType>::DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) {
AMS_UNUSED(old_path, new_path);
return fs::ResultUnsupportedOperationInPartitionFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA());
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::DoRenameFile(const char *old_path, const char *new_path) {
Result PartitionFileSystemCore<MetaType>::DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) {
AMS_UNUSED(old_path, new_path);
return fs::ResultUnsupportedOperationInPartitionFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemA());
}
template <typename MetaType>
Result PartitionFileSystemCore<MetaType>::DoCommitProvisionally(s64 counter) {
AMS_UNUSED(counter);
return fs::ResultUnsupportedOperationInPartitionFileSystemB();
R_THROW(fs::ResultUnsupportedOperationInPartitionFileSystemB());
}
template class PartitionFileSystemCore<PartitionFileSystemMeta>;

View File

@@ -37,26 +37,26 @@ namespace ams::fssystem {
virtual ~RomFsFile() { /* ... */ }
public:
virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override {
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result {
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result {
size_t read_size = 0;
R_TRY(this->DryRead(std::addressof(read_size), offset, size, option, fs::OpenMode_Read));
R_TRY(m_parent->GetBaseStorage()->Read(offset + m_start, buffer, read_size));
*out = read_size;
return ResultSuccess();
R_SUCCEED();
}, AMS_CURRENT_FUNCTION_NAME));
return ResultSuccess();
R_SUCCEED();
}
virtual Result DoGetSize(s64 *out) override {
*out = this->GetSize();
return ResultSuccess();
R_SUCCEED();
}
virtual Result DoFlush() override {
return ResultSuccess();
R_SUCCEED();
}
virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override {
@@ -66,12 +66,12 @@ namespace ams::fssystem {
R_TRY(this->DryWrite(std::addressof(needs_append), offset, size, option, fs::OpenMode_Read));
AMS_ASSERT(needs_append == false);
return fs::ResultUnsupportedOperationInRomFsFileA();
R_THROW(fs::ResultUnsupportedOperationInRomFsFileA());
}
virtual Result DoSetSize(s64 size) override {
R_TRY(this->DrySetSize(size, fs::OpenMode_Read));
return fs::ResultUnsupportedOperationInRomFsFileA();
R_THROW(fs::ResultUnsupportedOperationInRomFsFileA());
}
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 {
@@ -87,14 +87,14 @@ namespace ams::fssystem {
operate_size = this->GetSize() - offset;
}
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result {
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result {
R_TRY(m_parent->GetBaseStorage()->OperateRange(dst, dst_size, op_id, m_start + offset, operate_size, src, src_size));
return ResultSuccess();
R_SUCCEED();
}, AMS_CURRENT_FUNCTION_NAME));
return ResultSuccess();
R_SUCCEED();
}
default:
return fs::ResultUnsupportedOperationInRomFsFileB();
R_THROW(fs::ResultUnsupportedOperationInRomFsFileB());
}
}
public:
@@ -115,21 +115,21 @@ namespace ams::fssystem {
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, fs::DirectoryEntry *out_entries, s64 max_entries) {
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result {
return this->ReadInternal(out_count, std::addressof(m_current_find), out_entries, max_entries);
virtual Result DoRead(s64 *out_count, fs::DirectoryEntry *out_entries, s64 max_entries) override {
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result {
R_RETURN(this->ReadInternal(out_count, std::addressof(m_current_find), out_entries, max_entries));
}, AMS_CURRENT_FUNCTION_NAME));
return ResultSuccess();
R_SUCCEED();
}
virtual Result DoGetEntryCount(s64 *out) {
virtual Result DoGetEntryCount(s64 *out) override {
FindPosition find = m_first_find;
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result {
R_TRY(this->ReadInternal(out, std::addressof(find), nullptr, 0));
return ResultSuccess();
R_SUCCEED();
}, AMS_CURRENT_FUNCTION_NAME));
return ResultSuccess();
R_SUCCEED();
}
private:
Result ReadInternal(s64 *out_count, FindPosition *find, fs::DirectoryEntry *out_entries, s64 max_entries) {
@@ -179,7 +179,7 @@ namespace ams::fssystem {
}
*out_count = i;
return ResultSuccess();
R_SUCCEED();
}
public:
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override {
@@ -211,11 +211,11 @@ namespace ams::fssystem {
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result {
R_TRY(storage->Read(0, std::addressof(header), sizeof(header)));
return ResultSuccess();
R_SUCCEED();
}, AMS_CURRENT_FUNCTION_NAME));
*out = CalculateRequiredWorkingMemorySize(header);
return ResultSuccess();
R_SUCCEED();
}
Result RomFsFileSystem::Initialize(fs::IStorage *base, void *work, size_t work_size, bool use_cache) {
@@ -272,93 +272,99 @@ namespace ams::fssystem {
/* Set members. */
m_entry_size = header.body_offset;
m_base_storage = base;
return ResultSuccess();
R_SUCCEED();
}
Result RomFsFileSystem::Initialize(std::shared_ptr<fs::IStorage> base, void *work, size_t work_size, bool use_cache) {
m_shared_storage = std::move(base);
return this->Initialize(m_shared_storage.get(), work, work_size, use_cache);
R_RETURN(this->Initialize(m_shared_storage.get(), work, work_size, use_cache));
}
Result RomFsFileSystem::GetFileInfo(RomFileTable::FileInfo *out, const char *path) {
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result {
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result {
R_TRY_CATCH(m_rom_file_table.OpenFile(out, path)) {
R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound());
R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound());
} R_END_TRY_CATCH;
return ResultSuccess();
R_SUCCEED();
}, AMS_CURRENT_FUNCTION_NAME));
return ResultSuccess();
R_SUCCEED();
}
Result RomFsFileSystem::GetFileBaseOffset(s64 *out, const char *path) {
Result RomFsFileSystem::GetFileBaseOffset(s64 *out, const fs::Path &path) {
R_TRY(this->CheckPathFormat(path));
RomFileTable::FileInfo info;
R_TRY(this->GetFileInfo(std::addressof(info), path));
*out = m_entry_size + info.offset.Get();
return ResultSuccess();
R_SUCCEED();
}
Result RomFsFileSystem::DoCreateFile(const char *path, s64 size, int flags) {
Result RomFsFileSystem::DoCreateFile(const fs::Path &path, s64 size, int flags) {
AMS_UNUSED(path, size, flags);
return fs::ResultUnsupportedOperationInRomFsFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA());
}
Result RomFsFileSystem::DoDeleteFile(const char *path) {
Result RomFsFileSystem::DoDeleteFile(const fs::Path &path) {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInRomFsFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA());
}
Result RomFsFileSystem::DoCreateDirectory(const char *path) {
Result RomFsFileSystem::DoCreateDirectory(const fs::Path &path) {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInRomFsFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA());
}
Result RomFsFileSystem::DoDeleteDirectory(const char *path) {
Result RomFsFileSystem::DoDeleteDirectory(const fs::Path &path) {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInRomFsFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA());
}
Result RomFsFileSystem::DoDeleteDirectoryRecursively(const char *path) {
Result RomFsFileSystem::DoDeleteDirectoryRecursively(const fs::Path &path) {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInRomFsFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA());
}
Result RomFsFileSystem::DoRenameFile(const char *old_path, const char *new_path) {
Result RomFsFileSystem::DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) {
AMS_UNUSED(old_path, new_path);
return fs::ResultUnsupportedOperationInRomFsFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA());
}
Result RomFsFileSystem::DoRenameDirectory(const char *old_path, const char *new_path) {
Result RomFsFileSystem::DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) {
AMS_UNUSED(old_path, new_path);
return fs::ResultUnsupportedOperationInRomFsFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA());
}
Result RomFsFileSystem::DoGetEntryType(fs::DirectoryEntryType *out, const char *path) {
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result {
Result RomFsFileSystem::DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) {
R_TRY(this->CheckPathFormat(path));
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result {
fs::RomDirectoryInfo dir_info;
R_TRY_CATCH(m_rom_file_table.GetDirectoryInformation(std::addressof(dir_info), path)) {
R_TRY_CATCH(m_rom_file_table.GetDirectoryInformation(std::addressof(dir_info), path.GetString())) {
R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound())
R_CATCH(fs::ResultDbmInvalidOperation) {
RomFileTable::FileInfo file_info;
R_TRY(this->GetFileInfo(std::addressof(file_info), path));
*out = fs::DirectoryEntryType_File;
return ResultSuccess();
R_SUCCEED();
}
} R_END_TRY_CATCH;
*out = fs::DirectoryEntryType_Directory;
return ResultSuccess();
R_SUCCEED();
}, AMS_CURRENT_FUNCTION_NAME));
return ResultSuccess();
R_SUCCEED();
}
Result RomFsFileSystem::DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) {
Result RomFsFileSystem::DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) {
R_UNLESS(mode == fs::OpenMode_Read, fs::ResultInvalidOpenMode());
R_TRY(this->CheckPathFormat(path));
RomFileTable::FileInfo file_info;
R_TRY(this->GetFileInfo(std::addressof(file_info), path));
@@ -366,45 +372,47 @@ namespace ams::fssystem {
R_UNLESS(file != nullptr, fs::ResultAllocationFailureInRomFsFileSystemC());
*out_file = std::move(file);
return ResultSuccess();
R_SUCCEED();
}
Result RomFsFileSystem::DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) {
Result RomFsFileSystem::DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) {
R_TRY(this->CheckPathFormat(path));
RomFileTable::FindPosition find;
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result {
R_TRY_CATCH(m_rom_file_table.FindOpen(std::addressof(find), path)) {
R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound())
R_TRY_CATCH(m_rom_file_table.FindOpen(std::addressof(find), path.GetString())) {
R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound())
} R_END_TRY_CATCH;
return ResultSuccess();
R_SUCCEED();
}, AMS_CURRENT_FUNCTION_NAME));
auto dir = std::make_unique<RomFsDirectory>(this, find, mode);
R_UNLESS(dir != nullptr, fs::ResultAllocationFailureInRomFsFileSystemD());
*out_dir = std::move(dir);
return ResultSuccess();
R_SUCCEED();
}
Result RomFsFileSystem::DoCommit() {
return ResultSuccess();
R_SUCCEED();
}
Result RomFsFileSystem::DoGetFreeSpaceSize(s64 *out, const char *path) {
Result RomFsFileSystem::DoGetFreeSpaceSize(s64 *out, const fs::Path &path) {
AMS_UNUSED(path);
*out = 0;
return ResultSuccess();
R_SUCCEED();
}
Result RomFsFileSystem::DoCleanDirectoryRecursively(const char *path) {
Result RomFsFileSystem::DoCleanDirectoryRecursively(const fs::Path &path) {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInRomFsFileSystemA();
R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemA());
}
Result RomFsFileSystem::DoCommitProvisionally(s64 counter) {
AMS_UNUSED(counter);
return fs::ResultUnsupportedOperationInRomFsFileSystemB();
R_THROW(fs::ResultUnsupportedOperationInRomFsFileSystemB());
}
}

View File

@@ -1,82 +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::fssystem {
SubDirectoryFileSystem::SubDirectoryFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs, const char *bp, bool unc)
: PathResolutionFileSystem(fs, unc)
{
m_base_path = nullptr;
R_ABORT_UNLESS(this->Initialize(bp));
}
SubDirectoryFileSystem::SubDirectoryFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs, const char *bp, bool unc)
: PathResolutionFileSystem(std::move(fs), unc)
{
m_base_path = nullptr;
R_ABORT_UNLESS(this->Initialize(bp));
}
SubDirectoryFileSystem::~SubDirectoryFileSystem() {
if (m_base_path != nullptr) {
fs::impl::Deallocate(m_base_path, m_base_path_len);
}
}
Result SubDirectoryFileSystem::Initialize(const char *bp) {
/* Make sure the path isn't too long. */
R_UNLESS(strnlen(bp, fs::EntryNameLengthMax + 1) <= fs::EntryNameLengthMax, fs::ResultTooLongPath());
/* Normalize the path. */
char normalized_path[fs::EntryNameLengthMax + 2];
size_t normalized_path_len;
R_TRY(fs::PathNormalizer::Normalize(normalized_path, std::addressof(normalized_path_len), bp, sizeof(normalized_path), this->IsUncPreserved()));
/* Ensure terminating '/' */
if (!fs::PathNormalizer::IsSeparator(normalized_path[normalized_path_len - 1])) {
AMS_ASSERT(normalized_path_len + 2 < sizeof(normalized_path));
normalized_path[normalized_path_len] = fs::StringTraits::DirectorySeparator;
normalized_path[normalized_path_len + 1] = fs::StringTraits::NullTerminator;
++normalized_path_len;
}
/* Allocate new path. */
m_base_path_len = normalized_path_len + 1;
m_base_path = static_cast<char *>(fs::impl::Allocate(m_base_path_len));
R_UNLESS(m_base_path != nullptr, fs::ResultAllocationFailureInSubDirectoryFileSystem());
/* Copy path in. */
std::memcpy(m_base_path, normalized_path, normalized_path_len);
m_base_path[normalized_path_len] = fs::StringTraits::NullTerminator;
return ResultSuccess();
}
Result SubDirectoryFileSystem::ResolveFullPath(char *out, size_t out_size, const char *relative_path) {
/* Ensure path will fit. */
R_UNLESS(m_base_path_len + strnlen(relative_path, fs::EntryNameLengthMax + 1) <= out_size, fs::ResultTooLongPath());
/* Copy base path. */
std::memcpy(out, m_base_path, m_base_path_len);
/* Normalize it. */
const size_t prefix_size = m_base_path_len - 2;
size_t normalized_len;
return fs::PathNormalizer::Normalize(out + prefix_size, std::addressof(normalized_len), relative_path, out_size - prefix_size, this->IsUncPreserved(), false);
}
}

View File

@@ -19,39 +19,43 @@ namespace ams::fssystem {
namespace {
inline Result EnsureDirectory(fs::fsa::IFileSystem *fs, const char *path) {
R_TRY_CATCH(fs->CreateDirectory(path)) {
R_CATCH(fs::ResultPathAlreadyExists) { /* If path already exists, there's no problem. */ }
} R_END_TRY_CATCH;
Result EnsureDirectoryImpl(fs::fsa::IFileSystem *fs, const fs::Path &path) {
/* Create work path. */
fs::Path work_path;
R_TRY(work_path.Initialize(path));
return ResultSuccess();
/* Create a directory path parser. */
fs::DirectoryPathParser parser;
R_TRY(parser.Initialize(std::addressof(work_path)));
bool is_finished;
do {
/* Get the current path. */
const fs::Path &cur_path = parser.GetCurrentPath();
/* Get the entry type for the current path. */
fs::DirectoryEntryType type;
R_TRY_CATCH(fs->GetEntryType(std::addressof(type), cur_path)) {
R_CATCH(fs::ResultPathNotFound) {
/* The path doesn't exist. We should create it. */
R_TRY(fs->CreateDirectory(cur_path));
/* Get the updated entry type. */
R_TRY(fs->GetEntryType(std::addressof(type), cur_path));
}
} R_END_TRY_CATCH;
/* Verify that the current entry isn't a file. */
R_UNLESS(type != fs::DirectoryEntryType_File, fs::ResultPathAlreadyExists());
/* Advance to the next part of the path. */
R_TRY(parser.ReadNext(std::addressof(is_finished)));
} while (!is_finished);
R_SUCCEED();
}
Result EnsureDirectoryRecursivelyImpl(fs::fsa::IFileSystem *fs, const char *path, bool create_last) {
/* Normalize the path. */
char normalized_path[fs::EntryNameLengthMax + 1];
size_t normalized_path_len;
R_TRY(fs::PathNormalizer::Normalize(normalized_path, std::addressof(normalized_path_len), path, sizeof(normalized_path)));
/* Repeatedly call CreateDirectory on each directory leading to the target. */
for (size_t i = 1; i < normalized_path_len; i++) {
/* If we detect a separator, create the directory. */
if (fs::PathNormalizer::IsSeparator(normalized_path[i])) {
normalized_path[i] = fs::StringTraits::NullTerminator;
R_TRY(EnsureDirectory(fs, normalized_path));
normalized_path[i] = fs::StringTraits::DirectorySeparator;
}
}
/* Create the last directory if requested. */
if (create_last) {
R_TRY(EnsureDirectory(fs, normalized_path));
}
return ResultSuccess();
}
Result HasEntry(bool *out, fs::fsa::IFileSystem *fsa, const char *path, fs::DirectoryEntryType type) {
Result HasEntry(bool *out, fs::fsa::IFileSystem *fsa, const fs::Path &path, fs::DirectoryEntryType type) {
/* Set out to false initially. */
*out = false;
@@ -64,30 +68,27 @@ namespace ams::fssystem {
/* We succeeded. */
*out = entry_type == type;
return ResultSuccess();
R_SUCCEED();
}
}
Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *entry, void *work_buf, size_t work_buf_size) {
Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const fs::Path &dst_path, const fs::Path &src_path, void *work_buf, size_t work_buf_size) {
/* Open source file. */
std::unique_ptr<fs::fsa::IFile> src_file;
R_TRY(src_fs->OpenFile(std::addressof(src_file), src_path, fs::OpenMode_Read));
/* Get the file size. */
s64 file_size;
R_TRY(src_file->GetSize(std::addressof(file_size)));
/* Open dst file. */
std::unique_ptr<fs::fsa::IFile> dst_file;
{
char dst_path[fs::EntryNameLengthMax + 1];
const size_t original_size = static_cast<size_t>(util::SNPrintf(dst_path, sizeof(dst_path), "%s%s", dst_parent_path, entry->name));
/* TODO: Error code? N aborts here. */
AMS_ABORT_UNLESS(original_size < sizeof(dst_path));
R_TRY(dst_fs->CreateFile(dst_path, entry->file_size));
R_TRY(dst_fs->OpenFile(std::addressof(dst_file), dst_path, fs::OpenMode_Write));
}
R_TRY(dst_fs->CreateFile(dst_path, file_size));
R_TRY(dst_fs->OpenFile(std::addressof(dst_file), dst_path, fs::OpenMode_Write));
/* Read/Write file in work buffer sized chunks. */
s64 remaining = entry->file_size;
s64 remaining = file_size;
s64 offset = 0;
while (remaining > 0) {
size_t read_size;
@@ -98,59 +99,63 @@ namespace ams::fssystem {
offset += read_size;
}
return ResultSuccess();
R_SUCCEED();
}
Result CopyDirectoryRecursively(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size) {
char dst_path_buf[fs::EntryNameLengthMax + 1];
const size_t original_size = static_cast<size_t>(util::SNPrintf(dst_path_buf, sizeof(dst_path_buf), "%s", dst_path));
AMS_ABORT_UNLESS(original_size < sizeof(dst_path_buf));
Result CopyDirectoryRecursively(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const fs::Path &dst_path, const fs::Path &src_path, fs::DirectoryEntry *entry, void *work_buf, size_t work_buf_size) {
/* Set up the destination work path to point at the target directory. */
fs::Path dst_work_path;
R_TRY(dst_work_path.Initialize(dst_path));
return IterateDirectoryRecursively(src_fs, src_path,
[&](const char *path, const fs::DirectoryEntry &entry) -> Result { /* On Enter Directory */
AMS_UNUSED(path);
/* Update path, create new dir. */
std::strncat(dst_path_buf, entry.name, sizeof(dst_path_buf) - strnlen(dst_path_buf, sizeof(dst_path_buf) - 1) - 1);
std::strncat(dst_path_buf, "/", sizeof(dst_path_buf) - strnlen(dst_path_buf, sizeof(dst_path_buf) - 1) - 1);
return dst_fs->CreateDirectory(dst_path_buf);
},
[&](const char *path, const fs::DirectoryEntry &entry) -> Result { /* On Exit Directory */
/* Iterate, copying files. */
R_RETURN(IterateDirectoryRecursively(src_fs, src_path, entry,
[&](const fs::Path &path, const fs::DirectoryEntry &entry) -> Result { /* On Enter Directory */
AMS_UNUSED(path, entry);
/* Check we have a parent directory. */
const size_t len = strnlen(dst_path_buf, sizeof(dst_path_buf));
R_UNLESS(len >= 2, fs::ResultInvalidPathFormat());
/* Append the current entry to the dst work path. */
R_TRY(dst_work_path.AppendChild(entry.name));
/* Find previous separator, add null terminator */
char *cur = dst_path_buf + len - 2;
while (!fs::PathNormalizer::IsSeparator(*cur) && cur > dst_path_buf) {
cur--;
}
cur[1] = fs::StringTraits::NullTerminator;
return ResultSuccess();
/* Create the directory. */
R_RETURN(dst_fs->CreateDirectory(dst_work_path));
},
[&](const char *path, const fs::DirectoryEntry &entry) -> Result { /* On File */
return CopyFile(dst_fs, src_fs, dst_path_buf, path, std::addressof(entry), work_buf, work_buf_size);
[&](const fs::Path &path, const fs::DirectoryEntry &entry) -> Result { /* On Exit Directory */
AMS_UNUSED(path, entry);
/* Remove the directory we're leaving from the dst work path. */
R_RETURN(dst_work_path.RemoveChild());
},
[&](const fs::Path &path, const fs::DirectoryEntry &entry) -> Result { /* On File */
/* Append the current entry to the dst work path. */
R_TRY(dst_work_path.AppendChild(entry.name));
/* Copy the file. */
R_TRY(fssystem::CopyFile(dst_fs, src_fs, dst_work_path, path, work_buf, work_buf_size));
/* Remove the current entry from the dst work path. */
R_RETURN(dst_work_path.RemoveChild());
}
);
));
}
Result HasFile(bool *out, fs::fsa::IFileSystem *fs, const char *path) {
return HasEntry(out, fs, path, fs::DirectoryEntryType_File);
Result HasFile(bool *out, fs::fsa::IFileSystem *fs, const fs::Path &path) {
R_RETURN(HasEntry(out, fs, path, fs::DirectoryEntryType_File));
}
Result HasDirectory(bool *out, fs::fsa::IFileSystem *fs, const char *path) {
return HasEntry(out, fs, path, fs::DirectoryEntryType_Directory);
Result HasDirectory(bool *out, fs::fsa::IFileSystem *fs, const fs::Path &path) {
R_RETURN(HasEntry(out, fs, path, fs::DirectoryEntryType_Directory));
}
Result EnsureDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path) {
return EnsureDirectoryRecursivelyImpl(fs, path, true);
}
Result EnsureDirectory(fs::fsa::IFileSystem *fs, const fs::Path &path) {
/* First, check if the directory already exists. If it does, we're good to go. */
fs::DirectoryEntryType type;
R_TRY_CATCH(fs->GetEntryType(std::addressof(type), path)) {
/* If the directory doesn't already exist, we should create it. */
R_CATCH(fs::ResultPathNotFound) {
R_TRY(EnsureDirectoryImpl(fs, path));
}
} R_END_TRY_CATCH;
Result EnsureParentDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path) {
return EnsureDirectoryRecursivelyImpl(fs, path, false);
R_SUCCEED();
}
void AddCounter(void *_counter, size_t counter_size, u64 value) {

View File

@@ -167,7 +167,7 @@ namespace ams::fssystem::save {
/* Initialize the top level verification storage. */
{
fs::HashSalt mac;
crypto::GenerateHmacSha256Mac(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[0].key, KeyArray[0].size);
crypto::GenerateHmacSha256(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[0].key, KeyArray[0].size);
m_verify_storages[0].Initialize(storage[HierarchicalStorageInformation::MasterStorage], storage[HierarchicalStorageInformation::Layer1Storage], static_cast<s64>(1) << info.info[0].block_order, HashSize, m_buffers->buffers[m_max_layers - 2], hgf, mac, false, storage_type);
}
@@ -202,7 +202,7 @@ namespace ams::fssystem::save {
{
fs::SubStorage buffer_storage(std::addressof(m_buffer_storages[level]), 0, info.info[level].size);
fs::HashSalt mac;
crypto::GenerateHmacSha256Mac(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[level + 1].key, KeyArray[level + 1].size);
crypto::GenerateHmacSha256(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[level + 1].key, KeyArray[level + 1].size);
m_verify_storages[level + 1].Initialize(buffer_storage, storage[level + 2], static_cast<s64>(1) << info.info[level + 1].block_order, static_cast<s64>(1) << info.info[level].block_order, m_buffers->buffers[m_max_layers - 2], hgf, mac, false, storage_type);
}
@@ -216,7 +216,7 @@ namespace ams::fssystem::save {
{
fs::SubStorage buffer_storage(std::addressof(m_buffer_storages[level]), 0, info.info[level].size);
fs::HashSalt mac;
crypto::GenerateHmacSha256Mac(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[level + 1].key, KeyArray[level + 1].size);
crypto::GenerateHmacSha256(mac.value, sizeof(mac), info.seed.value, sizeof(info.seed), KeyArray[level + 1].key, KeyArray[level + 1].size);
m_verify_storages[level + 1].Initialize(buffer_storage, storage[level + 2], static_cast<s64>(1) << info.info[level + 1].block_order, static_cast<s64>(1) << info.info[level].block_order, m_buffers->buffers[m_max_layers - 2], hgf, mac, true, storage_type);
}