ams: support building unit test programs on windows/linux/macos
This commit is contained in:
@@ -80,8 +80,8 @@ namespace ams::fssystem {
|
||||
return this->GetRetriedCountImpl();
|
||||
}
|
||||
|
||||
void ClearPeak() const {
|
||||
return this->ClearPeak();
|
||||
void ClearPeak() {
|
||||
return this->ClearPeakImpl();
|
||||
}
|
||||
protected:
|
||||
virtual const std::pair<uintptr_t, size_t> AllocateBufferImpl(size_t size, const BufferAttribute &attr) = 0;
|
||||
|
||||
@@ -14,34 +14,166 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere/fssystem/impl/fssystem_path_resolution_filesystem.hpp>
|
||||
#include <stratosphere/fs/fs_common.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifile.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_idirectory.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
|
||||
#include <stratosphere/fs/impl/fs_newable.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
class DirectoryRedirectionFileSystem : public impl::IPathResolutionFileSystem<DirectoryRedirectionFileSystem> {
|
||||
class DirectoryRedirectionFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable {
|
||||
NON_COPYABLE(DirectoryRedirectionFileSystem);
|
||||
private:
|
||||
using PathResolutionFileSystem = impl::IPathResolutionFileSystem<DirectoryRedirectionFileSystem>;
|
||||
friend class impl::IPathResolutionFileSystem<DirectoryRedirectionFileSystem>;
|
||||
private:
|
||||
char *m_before_dir;
|
||||
size_t m_before_dir_len;
|
||||
char *m_after_dir;
|
||||
size_t m_after_dir_len;
|
||||
std::unique_ptr<fs::fsa::IFileSystem> m_base_fs;
|
||||
fs::Path m_before_dir;
|
||||
fs::Path m_after_dir;
|
||||
public:
|
||||
DirectoryRedirectionFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs, const char *before, const char *after, bool unc = false);
|
||||
DirectoryRedirectionFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs, const char *before, const char *after, bool unc = false);
|
||||
DirectoryRedirectionFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs) : m_base_fs(std::move(fs)), m_before_dir(), m_after_dir() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
virtual ~DirectoryRedirectionFileSystem();
|
||||
protected:
|
||||
inline util::optional<std::scoped_lock<os::SdkMutex>> GetAccessorLock() const {
|
||||
/* No accessor lock is needed. */
|
||||
return util::nullopt;
|
||||
Result InitializeWithFixedPath(const char *before, const char *after) {
|
||||
R_TRY(fs::SetUpFixedPath(std::addressof(m_before_dir), before));
|
||||
R_TRY(fs::SetUpFixedPath(std::addressof(m_after_dir), after));
|
||||
R_SUCCEED();
|
||||
}
|
||||
private:
|
||||
Result GetNormalizedDirectoryPath(char **out, size_t *out_size, const char *dir);
|
||||
Result Initialize(const char *before, const char *after);
|
||||
Result ResolveFullPath(char *out, size_t out_size, const char *relative_path);
|
||||
Result ResolveFullPath(fs::Path *out, const fs::Path &path) {
|
||||
if (path.IsMatchHead(m_before_dir.GetString(), m_before_dir.GetLength())) {
|
||||
R_TRY(out->InitializeWithFormat("%s%s", m_after_dir.GetString(), path.GetString() + m_before_dir.GetLength()));
|
||||
R_TRY(out->Normalize(fs::PathFlags{}));
|
||||
} else {
|
||||
R_TRY(out->Initialize(path));
|
||||
}
|
||||
R_SUCCEED();
|
||||
}
|
||||
public:
|
||||
virtual Result DoCreateFile(const fs::Path &path, s64 size, int option) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->CreateFile(full_path, size, option));
|
||||
}
|
||||
|
||||
virtual Result DoDeleteFile(const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->DeleteFile(full_path));
|
||||
}
|
||||
|
||||
virtual Result DoCreateDirectory(const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->CreateDirectory(full_path));
|
||||
}
|
||||
|
||||
virtual Result DoDeleteDirectory(const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->DeleteDirectory(full_path));
|
||||
}
|
||||
|
||||
virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->DeleteDirectoryRecursively(full_path));
|
||||
}
|
||||
|
||||
virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override {
|
||||
fs::Path old_full_path;
|
||||
fs::Path new_full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(old_full_path), old_path));
|
||||
R_TRY(this->ResolveFullPath(std::addressof(new_full_path), new_path));
|
||||
|
||||
R_RETURN(m_base_fs->RenameFile(old_full_path, new_full_path));
|
||||
}
|
||||
|
||||
virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override {
|
||||
fs::Path old_full_path;
|
||||
fs::Path new_full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(old_full_path), old_path));
|
||||
R_TRY(this->ResolveFullPath(std::addressof(new_full_path), new_path));
|
||||
|
||||
R_RETURN(m_base_fs->RenameDirectory(old_full_path, new_full_path));
|
||||
}
|
||||
|
||||
virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->GetEntryType(out, full_path));
|
||||
}
|
||||
|
||||
virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->OpenFile(out_file, full_path, mode));
|
||||
}
|
||||
|
||||
virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->OpenDirectory(out_dir, full_path, mode));
|
||||
}
|
||||
|
||||
virtual Result DoCommit() override {
|
||||
R_RETURN(m_base_fs->Commit());
|
||||
}
|
||||
|
||||
virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->GetFreeSpaceSize(out, full_path));
|
||||
}
|
||||
|
||||
virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->GetTotalSpaceSize(out, full_path));
|
||||
}
|
||||
|
||||
virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->CleanDirectoryRecursively(full_path));
|
||||
}
|
||||
|
||||
virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->GetFileTimeStampRaw(out, full_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 {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->QueryEntry(dst, dst_size, src, src_size, query, full_path));
|
||||
}
|
||||
|
||||
/* These aren't accessible as commands. */
|
||||
virtual Result DoCommitProvisionally(s64 counter) override {
|
||||
R_RETURN(m_base_fs->CommitProvisionally(counter));
|
||||
}
|
||||
|
||||
virtual Result DoRollback() override {
|
||||
R_RETURN(m_base_fs->Rollback());
|
||||
}
|
||||
|
||||
virtual Result DoFlush() override {
|
||||
R_RETURN(m_base_fs->Flush());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -14,51 +14,56 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere/fssystem/impl/fssystem_path_resolution_filesystem.hpp>
|
||||
#include <stratosphere/fs/fs_common.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifile.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_idirectory.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
|
||||
#include <stratosphere/fs/impl/fs_newable.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
class DirectorySaveDataFileSystem : public impl::IPathResolutionFileSystem<DirectorySaveDataFileSystem> {
|
||||
class DirectorySaveDataFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable {
|
||||
NON_COPYABLE(DirectorySaveDataFileSystem);
|
||||
private:
|
||||
using PathResolutionFileSystem = impl::IPathResolutionFileSystem<DirectorySaveDataFileSystem>;
|
||||
friend class impl::IPathResolutionFileSystem<DirectorySaveDataFileSystem>;
|
||||
private:
|
||||
os::SdkMutex m_accessor_mutex;
|
||||
s32 m_open_writable_files;
|
||||
public:
|
||||
DirectorySaveDataFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs);
|
||||
DirectorySaveDataFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs);
|
||||
Result Initialize();
|
||||
std::unique_ptr<fs::fsa::IFileSystem> m_unique_fs;
|
||||
fs::fsa::IFileSystem * const m_base_fs;
|
||||
os::SdkMutex m_accessor_mutex = {};
|
||||
s32 m_open_writable_files = 0;
|
||||
bool m_is_journaling_supported = false;
|
||||
bool m_is_multi_commit_supported = false;
|
||||
bool m_is_journaling_enabled = false;
|
||||
|
||||
virtual ~DirectorySaveDataFileSystem();
|
||||
protected:
|
||||
inline util::optional<std::scoped_lock<os::SdkMutex>> GetAccessorLock() {
|
||||
/* We have a real accessor lock that we want to use. */
|
||||
return util::make_optional<std::scoped_lock<os::SdkMutex>>(m_accessor_mutex);
|
||||
}
|
||||
/* Extension member to ensure proper savedata locking. */
|
||||
std::unique_ptr<fs::fsa::IFile> m_lock_file = nullptr;
|
||||
public:
|
||||
DirectorySaveDataFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs) : m_unique_fs(std::move(fs)), m_base_fs(m_unique_fs.get()) { /* ... */ }
|
||||
DirectorySaveDataFileSystem(fs::fsa::IFileSystem *fs) : m_unique_fs(), m_base_fs(fs) { /* ... */ }
|
||||
Result Initialize(bool journaling_supported, bool multi_commit_enabled, bool journaling_enabled);
|
||||
private:
|
||||
Result AllocateWorkBuffer(std::unique_ptr<u8[]> *out, size_t *out_size, size_t ideal_size);
|
||||
Result SynchronizeDirectory(const char *dst, const char *src);
|
||||
Result ResolveFullPath(char *out, size_t out_size, const char *relative_path);
|
||||
Result SynchronizeDirectory(const fs::Path &dst, const fs::Path &src);
|
||||
Result ResolvePath(fs::Path *out, const fs::Path &path);
|
||||
Result AcquireLockFile();
|
||||
public:
|
||||
void OnWritableFileClose();
|
||||
Result CopySaveFromFileSystem(fs::fsa::IFileSystem *save_fs);
|
||||
void DecrementWriteOpenFileCount();
|
||||
public:
|
||||
/* Overridden from IPathResolutionFileSystem */
|
||||
virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) override;
|
||||
virtual Result DoCreateFile(const fs::Path &path, s64 size, int option) override;
|
||||
virtual Result DoDeleteFile(const fs::Path &path) override;
|
||||
virtual Result DoCreateDirectory(const fs::Path &path) override;
|
||||
virtual Result DoDeleteDirectory(const fs::Path &path) override;
|
||||
virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override;
|
||||
virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override;
|
||||
virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override;
|
||||
virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override;
|
||||
virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override;
|
||||
virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override;
|
||||
virtual Result DoCommit() override;
|
||||
virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override;
|
||||
virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override;
|
||||
virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override;
|
||||
|
||||
/* Overridden from IPathResolutionFileSystem but not commands. */
|
||||
/* These aren't accessible as commands. */
|
||||
virtual Result DoCommitProvisionally(s64 counter) override;
|
||||
virtual Result DoRollback() override;
|
||||
|
||||
/* Explicitly overridden to be not implemented. */
|
||||
virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override;
|
||||
virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override;
|
||||
virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const char *path) override;
|
||||
virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) override;
|
||||
virtual Result DoFlush() override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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 <vapours.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
|
||||
#include <stratosphere/fs/fs_memory_management.hpp>
|
||||
#include <stratosphere/fs/fs_path.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
/* TODO: Put this in its own header? */
|
||||
enum PathCaseSensitiveMode {
|
||||
PathCaseSensitiveMode_CaseInsensitive = 0,
|
||||
PathCaseSensitiveMode_CaseSensitive = 1,
|
||||
};
|
||||
|
||||
|
||||
class LocalFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable {
|
||||
NON_COPYABLE(LocalFileSystem);
|
||||
NON_MOVEABLE(LocalFileSystem);
|
||||
private:
|
||||
#if defined(ATMOSPHERE_OS_WINDOWS)
|
||||
using NativeCharacterType = wchar_t;
|
||||
#else
|
||||
using NativeCharacterType = char;
|
||||
#endif
|
||||
|
||||
using NativePathBuffer = std::unique_ptr<NativeCharacterType[], ::ams::fs::impl::Deleter>;
|
||||
private:
|
||||
fs::Path m_root_path;
|
||||
fssystem::PathCaseSensitiveMode m_case_sensitive_mode;
|
||||
NativePathBuffer m_native_path_buffer;
|
||||
int m_native_path_length;
|
||||
bool m_use_posix_time;
|
||||
public:
|
||||
LocalFileSystem(bool posix_time = true) : m_root_path(), m_native_path_buffer(), m_native_path_length(0), m_use_posix_time(posix_time) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
Result Initialize(const fs::Path &root_path, fssystem::PathCaseSensitiveMode case_sensitive_mode);
|
||||
|
||||
Result GetCaseSensitivePath(int *out_size, char *dst, size_t dst_size, const char *path, const char *work_path);
|
||||
private:
|
||||
Result CheckPathCaseSensitively(const NativeCharacterType *path, const NativeCharacterType *root_path, NativeCharacterType *cs_buf, size_t cs_size, bool check_case_sensitivity);
|
||||
Result ResolveFullPath(NativePathBuffer *out, const fs::Path &path, int max_len, int min_len, bool check_case_sensitivity);
|
||||
public:
|
||||
virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override;
|
||||
virtual Result DoDeleteFile(const fs::Path &path) override;
|
||||
virtual Result DoCreateDirectory(const fs::Path &path) override;
|
||||
virtual Result DoDeleteDirectory(const fs::Path &path) override;
|
||||
virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override;
|
||||
virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override;
|
||||
virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override;
|
||||
virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override;
|
||||
virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override;
|
||||
virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override;
|
||||
virtual Result DoCommit() override;
|
||||
virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override;
|
||||
virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override;
|
||||
virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override;
|
||||
virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) override;
|
||||
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;
|
||||
|
||||
/* These aren't accessible as commands. */
|
||||
virtual Result DoCommitProvisionally(s64 counter) override;
|
||||
virtual Result DoRollback() override;
|
||||
public:
|
||||
Result DoGetDiskFreeSpace(s64 *out_free, s64 *out_total, s64 *out_total_free, const fs::Path &path);
|
||||
Result DeleteDirectoryRecursivelyInternal(const NativeCharacterType *path, bool delete_top);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -49,18 +49,18 @@ namespace ams::fssystem {
|
||||
|
||||
Result GetFileBaseOffset(s64 *out_offset, const char *path);
|
||||
|
||||
virtual Result DoCreateFile(const char *path, s64 size, int option) override;
|
||||
virtual Result DoDeleteFile(const char *path) override;
|
||||
virtual Result DoCreateDirectory(const char *path) override;
|
||||
virtual Result DoDeleteDirectory(const char *path) override;
|
||||
virtual Result DoDeleteDirectoryRecursively(const char *path) override;
|
||||
virtual Result DoRenameFile(const char *old_path, const char *new_path) override;
|
||||
virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override;
|
||||
virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) override;
|
||||
virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) override;
|
||||
virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) override;
|
||||
virtual Result DoCreateFile(const fs::Path &path, s64 size, int option) override;
|
||||
virtual Result DoDeleteFile(const fs::Path &path) override;
|
||||
virtual Result DoCreateDirectory(const fs::Path &path) override;
|
||||
virtual Result DoDeleteDirectory(const fs::Path &path) override;
|
||||
virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override;
|
||||
virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override;
|
||||
virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override;
|
||||
virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override;
|
||||
virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override;
|
||||
virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override;
|
||||
virtual Result DoCommit() override;
|
||||
virtual Result DoCleanDirectoryRecursively(const char *path) override;
|
||||
virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override;
|
||||
|
||||
/* These aren't accessible as commands. */
|
||||
virtual Result DoCommitProvisionally(s64 counter) override;
|
||||
|
||||
@@ -31,10 +31,18 @@ namespace ams::fssystem {
|
||||
template<typename T, size_t Size>
|
||||
class Pimpl {
|
||||
private:
|
||||
alignas(0x10) u8 m_storage[Size];
|
||||
#if defined(ATMOSPHERE_OS_HORIZON) || defined(ATMOSPHERE_OS_WINDOWS) || defined(ATMOSPHERE_OS_LINUX)
|
||||
static constexpr size_t ExtraSizeToEnsureCompatibility = 0;
|
||||
#elif defined(ATMOSPHERE_OS_MACOS)
|
||||
static constexpr size_t ExtraSizeToEnsureCompatibility = 0x20;
|
||||
#endif
|
||||
|
||||
static constexpr size_t StorageSize = Size + ExtraSizeToEnsureCompatibility;
|
||||
private:
|
||||
alignas(0x10) u8 m_storage[StorageSize];
|
||||
public:
|
||||
ALWAYS_INLINE Pimpl() { impl::PimplHelper<T, Size>::Construct(m_storage); }
|
||||
ALWAYS_INLINE ~Pimpl() { impl::PimplHelper<T, Size>::Destroy(m_storage); }
|
||||
ALWAYS_INLINE Pimpl() { impl::PimplHelper<T, StorageSize>::Construct(m_storage); }
|
||||
ALWAYS_INLINE ~Pimpl() { impl::PimplHelper<T, StorageSize>::Destroy(m_storage); }
|
||||
|
||||
ALWAYS_INLINE T *Get() { return reinterpret_cast<T *>(m_storage + 0); }
|
||||
ALWAYS_INLINE T *operator->() { return reinterpret_cast<T *>(m_storage + 0); }
|
||||
|
||||
@@ -37,6 +37,13 @@ namespace ams::fssystem {
|
||||
s64 m_entry_size;
|
||||
private:
|
||||
Result GetFileInfo(RomFileTable::FileInfo *out, const char *path);
|
||||
Result GetFileInfo(RomFileTable::FileInfo *out, const fs::Path &path) {
|
||||
R_RETURN(this->GetFileInfo(out, path.GetString()));
|
||||
}
|
||||
|
||||
Result CheckPathFormat(const fs::Path &path) const {
|
||||
R_RETURN(fs::PathFormatter::CheckPathFormat(path.GetString(), fs::PathFlags{}));
|
||||
}
|
||||
public:
|
||||
static Result GetRequiredWorkingMemorySize(size_t *out, fs::IStorage *storage);
|
||||
public:
|
||||
@@ -48,21 +55,21 @@ namespace ams::fssystem {
|
||||
|
||||
fs::IStorage *GetBaseStorage();
|
||||
RomFileTable *GetRomFileTable();
|
||||
Result GetFileBaseOffset(s64 *out, const char *path);
|
||||
Result GetFileBaseOffset(s64 *out, const fs::Path &path);
|
||||
public:
|
||||
virtual Result DoCreateFile(const char *path, s64 size, int flags) override;
|
||||
virtual Result DoDeleteFile(const char *path) override;
|
||||
virtual Result DoCreateDirectory(const char *path) override;
|
||||
virtual Result DoDeleteDirectory(const char *path) override;
|
||||
virtual Result DoDeleteDirectoryRecursively(const char *path) override;
|
||||
virtual Result DoRenameFile(const char *old_path, const char *new_path) override;
|
||||
virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override;
|
||||
virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) override;
|
||||
virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) override;
|
||||
virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) override;
|
||||
virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override;
|
||||
virtual Result DoDeleteFile(const fs::Path &path) override;
|
||||
virtual Result DoCreateDirectory(const fs::Path &path) override;
|
||||
virtual Result DoDeleteDirectory(const fs::Path &path) override;
|
||||
virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override;
|
||||
virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override;
|
||||
virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override;
|
||||
virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override;
|
||||
virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override;
|
||||
virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override;
|
||||
virtual Result DoCommit() override;
|
||||
virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override;
|
||||
virtual Result DoCleanDirectoryRecursively(const char *path) override;
|
||||
virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override;
|
||||
virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override;
|
||||
|
||||
/* These aren't accessible as commands. */
|
||||
virtual Result DoCommitProvisionally(s64 counter) override;
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace ams::fssystem {
|
||||
}
|
||||
|
||||
virtual void DoGenerateHash(void *dst, size_t dst_size, const void *src, size_t src_size) override {
|
||||
crypto::GenerateSha256Hash(dst, dst_size, src, src_size);
|
||||
crypto::GenerateSha256(dst, dst_size, src, src_size);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -14,31 +14,162 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere/fssystem/impl/fssystem_path_resolution_filesystem.hpp>
|
||||
#include <stratosphere/fs/fs_common.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifile.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_idirectory.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
|
||||
#include <stratosphere/fs/impl/fs_newable.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
class SubDirectoryFileSystem : public impl::IPathResolutionFileSystem<SubDirectoryFileSystem> {
|
||||
class SubDirectoryFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable {
|
||||
NON_COPYABLE(SubDirectoryFileSystem);
|
||||
private:
|
||||
using PathResolutionFileSystem = impl::IPathResolutionFileSystem<SubDirectoryFileSystem>;
|
||||
friend class impl::IPathResolutionFileSystem<SubDirectoryFileSystem>;
|
||||
private:
|
||||
char *m_base_path;
|
||||
size_t m_base_path_len;
|
||||
std::shared_ptr<fs::fsa::IFileSystem> m_shared_fs;
|
||||
fs::fsa::IFileSystem * const m_base_fs;
|
||||
fs::Path m_root_path;
|
||||
public:
|
||||
SubDirectoryFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs, const char *bp, bool unc = false);
|
||||
SubDirectoryFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs, const char *bp, bool unc = false);
|
||||
SubDirectoryFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs) : m_shared_fs(std::move(fs)), m_base_fs(m_shared_fs.get()), m_root_path() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
virtual ~SubDirectoryFileSystem();
|
||||
protected:
|
||||
inline util::optional<std::scoped_lock<os::SdkMutex>> GetAccessorLock() const {
|
||||
/* No accessor lock is needed. */
|
||||
return util::nullopt;
|
||||
SubDirectoryFileSystem(fs::fsa::IFileSystem *fs) : m_shared_fs(), m_base_fs(fs), m_root_path() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
Result Initialize(const fs::Path &path) {
|
||||
R_RETURN(m_root_path.Initialize(path));
|
||||
}
|
||||
private:
|
||||
Result Initialize(const char *bp);
|
||||
Result ResolveFullPath(char *out, size_t out_size, const char *relative_path);
|
||||
Result ResolveFullPath(fs::Path *out, const fs::Path &path) {
|
||||
R_RETURN(out->Combine(m_root_path, path));
|
||||
}
|
||||
public:
|
||||
virtual Result DoCreateFile(const fs::Path &path, s64 size, int option) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->CreateFile(full_path, size, option));
|
||||
}
|
||||
|
||||
virtual Result DoDeleteFile(const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->DeleteFile(full_path));
|
||||
}
|
||||
|
||||
virtual Result DoCreateDirectory(const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->CreateDirectory(full_path));
|
||||
}
|
||||
|
||||
virtual Result DoDeleteDirectory(const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->DeleteDirectory(full_path));
|
||||
}
|
||||
|
||||
virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->DeleteDirectoryRecursively(full_path));
|
||||
}
|
||||
|
||||
virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override {
|
||||
fs::Path old_full_path;
|
||||
fs::Path new_full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(old_full_path), old_path));
|
||||
R_TRY(this->ResolveFullPath(std::addressof(new_full_path), new_path));
|
||||
|
||||
R_RETURN(m_base_fs->RenameFile(old_full_path, new_full_path));
|
||||
}
|
||||
|
||||
virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override {
|
||||
fs::Path old_full_path;
|
||||
fs::Path new_full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(old_full_path), old_path));
|
||||
R_TRY(this->ResolveFullPath(std::addressof(new_full_path), new_path));
|
||||
|
||||
R_RETURN(m_base_fs->RenameDirectory(old_full_path, new_full_path));
|
||||
}
|
||||
|
||||
virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->GetEntryType(out, full_path));
|
||||
}
|
||||
|
||||
virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->OpenFile(out_file, full_path, mode));
|
||||
}
|
||||
|
||||
virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->OpenDirectory(out_dir, full_path, mode));
|
||||
}
|
||||
|
||||
virtual Result DoCommit() override {
|
||||
R_RETURN(m_base_fs->Commit());
|
||||
}
|
||||
|
||||
virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->GetFreeSpaceSize(out, full_path));
|
||||
}
|
||||
|
||||
virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->GetTotalSpaceSize(out, full_path));
|
||||
}
|
||||
|
||||
virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->CleanDirectoryRecursively(full_path));
|
||||
}
|
||||
|
||||
virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) override {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->GetFileTimeStampRaw(out, full_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 {
|
||||
fs::Path full_path;
|
||||
R_TRY(this->ResolveFullPath(std::addressof(full_path), path));
|
||||
|
||||
R_RETURN(m_base_fs->QueryEntry(dst, dst_size, src, src_size, query, full_path));
|
||||
}
|
||||
|
||||
/* These aren't accessible as commands. */
|
||||
virtual Result DoCommitProvisionally(s64 counter) override {
|
||||
R_RETURN(m_base_fs->CommitProvisionally(counter));
|
||||
}
|
||||
|
||||
virtual Result DoRollback() override {
|
||||
R_RETURN(m_base_fs->Rollback());
|
||||
}
|
||||
|
||||
virtual Result DoFlush() override {
|
||||
R_RETURN(m_base_fs->Flush());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -18,21 +18,24 @@
|
||||
#include <stratosphere/fs/fs_file.hpp>
|
||||
#include <stratosphere/fs/fs_directory.hpp>
|
||||
#include <stratosphere/fs/fs_filesystem.hpp>
|
||||
#include <stratosphere/fs/fs_path_utils.hpp>
|
||||
#include <stratosphere/fs/fs_path.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
namespace impl {
|
||||
|
||||
template<typename F>
|
||||
concept IterateDirectoryHandler = requires (F f, const fs::Path &path, const fs::DirectoryEntry &entry) {
|
||||
{ f(path, entry) } -> std::convertible_to<::ams::Result>;
|
||||
};
|
||||
|
||||
/* Iteration. */
|
||||
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
|
||||
Result IterateDirectoryRecursivelyImpl(fs::fsa::IFileSystem *fs, char *work_path, size_t work_path_size, fs::DirectoryEntry *dir_ent, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
|
||||
template<IterateDirectoryHandler OnEnterDir, IterateDirectoryHandler OnExitDir, IterateDirectoryHandler OnFile>
|
||||
Result IterateDirectoryRecursivelyImpl(fs::fsa::IFileSystem *fs, fs::Path &work_path, fs::DirectoryEntry *dir_ent, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
|
||||
/* Open the directory. */
|
||||
std::unique_ptr<fs::fsa::IDirectory> dir;
|
||||
R_TRY(fs->OpenDirectory(std::addressof(dir), work_path, fs::OpenDirectoryMode_All));
|
||||
|
||||
const size_t parent_len = strnlen(work_path, work_path_size - 1);
|
||||
|
||||
/* Read and handle entries. */
|
||||
while (true) {
|
||||
/* Read a single entry. */
|
||||
@@ -44,22 +47,15 @@ namespace ams::fssystem {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Validate child path size. */
|
||||
const size_t child_name_len = strnlen(dir_ent->name, sizeof(dir_ent->name) - 1);
|
||||
const bool is_dir = dir_ent->type == fs::DirectoryEntryType_Directory;
|
||||
const size_t separator_size = is_dir ? 1 : 0;
|
||||
R_UNLESS(parent_len + child_name_len + separator_size < work_path_size, fs::ResultTooLongPath());
|
||||
|
||||
/* Set child path. */
|
||||
std::strncat(work_path, dir_ent->name, work_path_size - parent_len - 1);
|
||||
/* Append child path. */
|
||||
R_TRY(work_path.AppendChild(dir_ent->name));
|
||||
{
|
||||
if (is_dir) {
|
||||
if (dir_ent->type == fs::DirectoryEntryType_Directory) {
|
||||
/* Enter directory. */
|
||||
R_TRY(on_enter_dir(work_path, *dir_ent));
|
||||
|
||||
/* Append separator, recurse. */
|
||||
std::strncat(work_path, "/", work_path_size - (parent_len + child_name_len) - 1);
|
||||
R_TRY(IterateDirectoryRecursivelyImpl(fs, work_path, work_path_size, dir_ent, on_enter_dir, on_exit_dir, on_file));
|
||||
/* Recurse. */
|
||||
R_TRY(IterateDirectoryRecursivelyImpl(fs, work_path, dir_ent, on_enter_dir, on_exit_dir, on_file));
|
||||
|
||||
/* Exit directory. */
|
||||
R_TRY(on_exit_dir(work_path, *dir_ent));
|
||||
@@ -68,12 +64,10 @@ namespace ams::fssystem {
|
||||
R_TRY(on_file(work_path, *dir_ent));
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore parent path. */
|
||||
work_path[parent_len] = fs::StringTraits::NullTerminator;
|
||||
R_TRY(work_path.RemoveChild());
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
/* TODO: Cleanup. */
|
||||
@@ -81,50 +75,39 @@ namespace ams::fssystem {
|
||||
}
|
||||
|
||||
/* Iteration API */
|
||||
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
|
||||
Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *root_path, char *work_path, size_t work_path_size, fs::DirectoryEntry *dir_ent_buf, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
|
||||
AMS_ABORT_UNLESS(work_path_size >= fs::EntryNameLengthMax + 1);
|
||||
template<impl::IterateDirectoryHandler OnEnterDir, impl::IterateDirectoryHandler OnExitDir, impl::IterateDirectoryHandler OnFile>
|
||||
Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, const fs::Path &root_path, fs::DirectoryEntry *dir_ent_buf, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
|
||||
/* Create work path from the root path. */
|
||||
fs::Path work_path;
|
||||
R_TRY(work_path.Initialize(root_path));
|
||||
|
||||
/* Get size of the root path. */
|
||||
size_t root_path_len = strnlen(root_path, fs::EntryNameLengthMax + 1);
|
||||
R_UNLESS(root_path_len <= fs::EntryNameLengthMax, fs::ResultTooLongPath());
|
||||
|
||||
/* Copy root path in, add a / if necessary. */
|
||||
std::memcpy(work_path, root_path, root_path_len);
|
||||
if (!fs::PathNormalizer::IsSeparator(work_path[root_path_len - 1])) {
|
||||
work_path[root_path_len++] = fs::StringTraits::DirectorySeparator;
|
||||
}
|
||||
|
||||
/* Make sure the result path is still valid. */
|
||||
R_UNLESS(root_path_len <= fs::EntryNameLengthMax, fs::ResultTooLongPath());
|
||||
work_path[root_path_len] = fs::StringTraits::NullTerminator;
|
||||
|
||||
return impl::IterateDirectoryRecursivelyImpl(fs, work_path, work_path_size, dir_ent_buf, on_enter_dir, on_exit_dir, on_file);
|
||||
R_RETURN(impl::IterateDirectoryRecursivelyImpl(fs, work_path, dir_ent_buf, on_enter_dir, on_exit_dir, on_file));
|
||||
}
|
||||
|
||||
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
|
||||
Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *root_path, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
|
||||
template<impl::IterateDirectoryHandler OnEnterDir, impl::IterateDirectoryHandler OnExitDir, impl::IterateDirectoryHandler OnFile>
|
||||
Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, const fs::Path &root_path, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
|
||||
fs::DirectoryEntry dir_entry = {};
|
||||
char work_path[fs::EntryNameLengthMax + 1] = {};
|
||||
return IterateDirectoryRecursively(fs, root_path, work_path, sizeof(work_path), std::addressof(dir_entry), on_enter_dir, on_exit_dir, on_file);
|
||||
return IterateDirectoryRecursively(fs, root_path, std::addressof(dir_entry), on_enter_dir, on_exit_dir, on_file);
|
||||
}
|
||||
|
||||
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
|
||||
template<impl::IterateDirectoryHandler OnEnterDir, impl::IterateDirectoryHandler OnExitDir, impl::IterateDirectoryHandler OnFile>
|
||||
Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
|
||||
return IterateDirectoryRecursively(fs, fs::PathNormalizer::RootPath, on_enter_dir, on_exit_dir, on_file);
|
||||
return IterateDirectoryRecursively(fs, fs::MakeConstantPath("/"), on_enter_dir, on_exit_dir, on_file);
|
||||
}
|
||||
|
||||
/* TODO: Cleanup API */
|
||||
|
||||
/* Copy API. */
|
||||
Result CopyFile(fs::fsa::IFileSystem *dst_fs, fs::fsa::IFileSystem *src_fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size);
|
||||
ALWAYS_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const char *dst_parent_path, const char *src_path, const fs::DirectoryEntry *dir_ent, void *work_buf, size_t work_buf_size) {
|
||||
return CopyFile(fs, fs, dst_parent_path, src_path, dir_ent, work_buf, 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);
|
||||
|
||||
ALWAYS_INLINE Result CopyFile(fs::fsa::IFileSystem *fs, const fs::Path &dst_path, const fs::Path &src_path, void *work_buf, size_t work_buf_size) {
|
||||
return CopyFile(fs, fs, dst_path, src_path, work_buf, work_buf_size);
|
||||
}
|
||||
|
||||
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);
|
||||
ALWAYS_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *dst_path, const char *src_path, void *work_buf, size_t work_buf_size) {
|
||||
return CopyDirectoryRecursively(fs, fs, dst_path, src_path, work_buf, work_buf_size);
|
||||
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);
|
||||
|
||||
ALWAYS_INLINE Result CopyDirectoryRecursively(fs::fsa::IFileSystem *fs, const fs::Path &dst_path, const fs::Path &src_path, fs::DirectoryEntry *entry, void *work_buf, size_t work_buf_size) {
|
||||
return CopyDirectoryRecursively(fs, fs, dst_path, src_path, entry, work_buf, work_buf_size);
|
||||
}
|
||||
|
||||
/* Semaphore adapter class. */
|
||||
@@ -142,32 +125,27 @@ namespace ams::fssystem {
|
||||
};
|
||||
|
||||
/* Other utility. */
|
||||
Result HasFile(bool *out, fs::fsa::IFileSystem *fs, const char *path);
|
||||
Result HasDirectory(bool *out, fs::fsa::IFileSystem *fs, const char *path);
|
||||
Result HasFile(bool *out, fs::fsa::IFileSystem *fs, const fs::Path &path);
|
||||
Result HasDirectory(bool *out, fs::fsa::IFileSystem *fs, const fs::Path &path);
|
||||
|
||||
Result EnsureDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path);
|
||||
Result EnsureParentDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path);
|
||||
Result EnsureDirectory(fs::fsa::IFileSystem *fs, const fs::Path &path);
|
||||
|
||||
template<s64 RetryMilliSeconds = 100>
|
||||
template<s64 RetryMilliSeconds = 100, s32 MaxTryCount = 10>
|
||||
ALWAYS_INLINE Result RetryFinitelyForTargetLocked(auto f) {
|
||||
/* Retry up to 10 times, 100ms between retries. */
|
||||
constexpr s32 MaxRetryCount = 10;
|
||||
/* Retry sleeping between retries. */
|
||||
constexpr TimeSpan RetryWaitTime = TimeSpan::FromMilliSeconds(RetryMilliSeconds);
|
||||
|
||||
s32 remaining_retries = MaxRetryCount;
|
||||
while (true) {
|
||||
R_TRY_CATCH(f()) {
|
||||
R_CATCH(fs::ResultTargetLocked) {
|
||||
R_UNLESS(remaining_retries > 0, fs::ResultTargetLocked());
|
||||
|
||||
remaining_retries--;
|
||||
os::SleepThread(RetryWaitTime);
|
||||
continue;
|
||||
}
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
return ResultSuccess();
|
||||
Result result = f();
|
||||
for (int i = 0; i < MaxTryCount && fs::ResultTargetLocked::Includes(result); ++i) {
|
||||
os::SleepThread(RetryWaitTime);
|
||||
result = f();
|
||||
}
|
||||
|
||||
R_RETURN(result);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result RetryToAvoidTargetLocked(auto f) {
|
||||
return RetryFinitelyForTargetLocked<2, 25>(f);
|
||||
}
|
||||
|
||||
void AddCounter(void *counter, size_t counter_size, u64 value);
|
||||
|
||||
@@ -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/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere/fs/fs_common.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifile.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_idirectory.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
|
||||
#include <stratosphere/fs/impl/fs_newable.hpp>
|
||||
|
||||
namespace ams::fssystem::impl {
|
||||
|
||||
template<typename Impl>
|
||||
class IPathResolutionFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable {
|
||||
NON_COPYABLE(IPathResolutionFileSystem);
|
||||
private:
|
||||
std::shared_ptr<fs::fsa::IFileSystem> m_shared_fs;
|
||||
std::unique_ptr<fs::fsa::IFileSystem> m_unique_fs;
|
||||
bool m_unc_preserved;
|
||||
protected:
|
||||
fs::fsa::IFileSystem * const m_base_fs;
|
||||
public:
|
||||
IPathResolutionFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs, bool unc = false) : m_shared_fs(std::move(fs)), m_unc_preserved(unc), m_base_fs(m_shared_fs.get()) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
IPathResolutionFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs, bool unc = false) : m_unique_fs(std::move(fs)), m_unc_preserved(unc), m_base_fs(m_unique_fs.get()) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
virtual ~IPathResolutionFileSystem() { /* ... */ }
|
||||
protected:
|
||||
constexpr inline bool IsUncPreserved() const {
|
||||
return m_unc_preserved;
|
||||
}
|
||||
public:
|
||||
virtual Result DoCreateFile(const char *path, s64 size, int option) override {
|
||||
char full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->CreateFile(full_path, size, option);
|
||||
}
|
||||
|
||||
virtual Result DoDeleteFile(const char *path) override {
|
||||
char full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->DeleteFile(full_path);
|
||||
}
|
||||
|
||||
virtual Result DoCreateDirectory(const char *path) override {
|
||||
char full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->CreateDirectory(full_path);
|
||||
}
|
||||
|
||||
virtual Result DoDeleteDirectory(const char *path) override {
|
||||
char full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->DeleteDirectory(full_path);
|
||||
}
|
||||
|
||||
virtual Result DoDeleteDirectoryRecursively(const char *path) override {
|
||||
char full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->DeleteDirectoryRecursively(full_path);
|
||||
}
|
||||
|
||||
virtual Result DoRenameFile(const char *old_path, const char *new_path) override {
|
||||
char old_full_path[fs::EntryNameLengthMax + 1];
|
||||
char new_full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(old_full_path, sizeof(old_full_path), old_path));
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(new_full_path, sizeof(new_full_path), new_path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->RenameFile(old_full_path, new_full_path);
|
||||
}
|
||||
|
||||
virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override {
|
||||
char old_full_path[fs::EntryNameLengthMax + 1];
|
||||
char new_full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(old_full_path, sizeof(old_full_path), old_path));
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(new_full_path, sizeof(new_full_path), new_path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->RenameDirectory(old_full_path, new_full_path);
|
||||
}
|
||||
|
||||
virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) override {
|
||||
char full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->GetEntryType(out, full_path);
|
||||
}
|
||||
|
||||
virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) override {
|
||||
char full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->OpenFile(out_file, full_path, mode);
|
||||
}
|
||||
|
||||
virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) override {
|
||||
char full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->OpenDirectory(out_dir, full_path, mode);
|
||||
}
|
||||
|
||||
virtual Result DoCommit() override {
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->Commit();
|
||||
}
|
||||
|
||||
virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override {
|
||||
char full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->GetFreeSpaceSize(out, full_path);
|
||||
}
|
||||
|
||||
virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override {
|
||||
char full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->GetTotalSpaceSize(out, full_path);
|
||||
}
|
||||
|
||||
virtual Result DoCleanDirectoryRecursively(const char *path) override {
|
||||
char full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->CleanDirectoryRecursively(full_path);
|
||||
}
|
||||
|
||||
virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const char *path) override {
|
||||
char full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->GetFileTimeStampRaw(out, full_path);
|
||||
}
|
||||
|
||||
virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) override {
|
||||
char full_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
|
||||
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->QueryEntry(dst, dst_size, src, src_size, query, full_path);
|
||||
}
|
||||
|
||||
/* These aren't accessible as commands. */
|
||||
virtual Result DoCommitProvisionally(s64 counter) override {
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->CommitProvisionally(counter);
|
||||
}
|
||||
|
||||
virtual Result DoRollback() override {
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->Rollback();
|
||||
}
|
||||
|
||||
virtual Result DoFlush() override {
|
||||
util::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
|
||||
return m_base_fs->Flush();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -105,7 +105,7 @@ namespace ams::fssystem::save {
|
||||
NON_COPYABLE(HierarchicalIntegrityVerificationStorage);
|
||||
NON_MOVEABLE(HierarchicalIntegrityVerificationStorage);
|
||||
private:
|
||||
friend class HierarchicalIntegrityVerificationMetaInformation;
|
||||
friend struct HierarchicalIntegrityVerificationMetaInformation;
|
||||
protected:
|
||||
static constexpr s64 HashSize = crypto::Sha256Generator::HashSize;
|
||||
static constexpr size_t MaxLayers = IntegrityMaxLayerCount;
|
||||
|
||||
Reference in New Issue
Block a user