subrepo:
  subdir:   "libraries"
  merged:   "07af583b"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "07af583b"
git-subrepo:
  version:  "0.4.0"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "5d6aba9"
This commit is contained in:
Michael Scire
2019-12-09 03:57:37 -08:00
committed by SciresM
parent 28717bfd27
commit 0105455086
294 changed files with 29915 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "impl/fssystem_path_resolution_filesystem.hpp"
namespace ams::fssystem {
class DirectoryRedirectionFileSystem : public impl::IPathResolutionFileSystem<DirectoryRedirectionFileSystem> {
NON_COPYABLE(DirectoryRedirectionFileSystem);
private:
using PathResolutionFileSystem = impl::IPathResolutionFileSystem<DirectoryRedirectionFileSystem>;
friend class impl::IPathResolutionFileSystem<DirectoryRedirectionFileSystem>;
private:
char *before_dir;
size_t before_dir_len;
char *after_dir;
size_t after_dir_len;
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);
virtual ~DirectoryRedirectionFileSystem();
protected:
inline std::optional<std::scoped_lock<os::Mutex>> GetAccessorLock() const {
/* No accessor lock is needed. */
return std::nullopt;
}
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);
};
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "impl/fssystem_path_resolution_filesystem.hpp"
namespace ams::fssystem {
class DirectorySaveDataFileSystem : public impl::IPathResolutionFileSystem<DirectorySaveDataFileSystem> {
NON_COPYABLE(DirectorySaveDataFileSystem);
private:
using PathResolutionFileSystem = impl::IPathResolutionFileSystem<DirectorySaveDataFileSystem>;
friend class impl::IPathResolutionFileSystem<DirectorySaveDataFileSystem>;
private:
os::Mutex accessor_mutex;
s32 open_writable_files;
public:
DirectorySaveDataFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs);
DirectorySaveDataFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs);
Result Initialize();
virtual ~DirectorySaveDataFileSystem();
protected:
inline std::optional<std::scoped_lock<os::Mutex>> GetAccessorLock() {
/* We have a real accessor lock that we want to use. */
return std::make_optional<std::scoped_lock<os::Mutex>>(this->accessor_mutex);
}
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);
public:
void OnWritableFileClose();
Result CopySaveFromFileSystem(fs::fsa::IFileSystem *save_fs);
public:
/* Overridden from IPathResolutionFileSystem */
virtual Result OpenFileImpl(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) override;
virtual Result CommitImpl() override;
/* Overridden from IPathResolutionFileSystem but not commands. */
virtual Result CommitProvisionallyImpl(s64 counter) override;
virtual Result RollbackImpl() override;
/* Explicitly overridden to be not implemented. */
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override;
virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override;
virtual Result GetFileTimeStampRawImpl(fs::FileTimeStampRaw *out, const char *path) override;
virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *path) override;
virtual Result FlushImpl() override;
};
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../fs/fs_common.hpp"
#include "../fs/fs_path_tool.hpp"
namespace ams::fssystem {
namespace StringTraits = ::ams::fs::StringTraits;
using PathTool = ::ams::fs::PathTool;
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "impl/fssystem_path_resolution_filesystem.hpp"
namespace ams::fssystem {
class SubDirectoryFileSystem : public impl::IPathResolutionFileSystem<SubDirectoryFileSystem> {
NON_COPYABLE(SubDirectoryFileSystem);
private:
using PathResolutionFileSystem = impl::IPathResolutionFileSystem<SubDirectoryFileSystem>;
friend class impl::IPathResolutionFileSystem<SubDirectoryFileSystem>;
private:
char *base_path;
size_t base_path_len;
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);
virtual ~SubDirectoryFileSystem();
protected:
inline std::optional<std::scoped_lock<os::Mutex>> GetAccessorLock() const {
/* No accessor lock is needed. */
return std::nullopt;
}
private:
Result Initialize(const char *bp);
Result ResolveFullPath(char *out, size_t out_size, const char *relative_path);
};
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../fs/fs_common.hpp"
#include "../fs/fs_file.hpp"
#include "../fs/fs_directory.hpp"
#include "../fs/fs_filesystem.hpp"
#include "fssystem_path_tool.hpp"
namespace ams::fssystem {
namespace impl {
/* 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) {
/* Open the directory. */
std::unique_ptr<fs::fsa::IDirectory> dir;
R_TRY(fs->OpenDirectory(&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. */
s64 read_count = 0;
R_TRY(dir->Read(&read_count, dir_ent, 1));
/* If we're out of entries, we're done. */
if (read_count == 0) {
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);
{
if (is_dir) {
/* 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));
/* Exit directory. */
R_TRY(on_exit_dir(work_path, *dir_ent));
} else {
/* Call file handler. */
R_TRY(on_file(work_path, *dir_ent));
}
}
/* Restore parent path. */
work_path[parent_len] = StringTraits::NullTerminator;
}
return ResultSuccess();
}
/* TODO: Cleanup. */
}
/* 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_ASSERT(work_path_size >= fs::EntryNameLengthMax + 1);
/* 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 (!PathTool::IsSeparator(work_path[root_path_len - 1])) {
work_path[root_path_len++] = StringTraits::DirectorySeparator;
}
/* Make sure the result path is still valid. */
R_UNLESS(root_path_len <= fs::EntryNameLengthMax, fs::ResultTooLongPath());
work_path[root_path_len] = StringTraits::NullTerminator;
return impl::IterateDirectoryRecursivelyImpl(fs, work_path, work_path_size, 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) {
fs::DirectoryEntry dir_entry = {};
char work_path[fs::EntryNameLengthMax + 1] = {};
return IterateDirectoryRecursively(fs, root_path, work_path, sizeof(work_path), &dir_entry, on_enter_dir, on_exit_dir, on_file);
}
template<typename OnEnterDir, typename OnExitDir, typename OnFile>
Result IterateDirectoryRecursively(fs::fsa::IFileSystem *fs, OnEnterDir on_enter_dir, OnExitDir on_exit_dir, OnFile on_file) {
return IterateDirectoryRecursively(fs, PathTool::RootPath, 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);
NX_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 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);
NX_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);
}
/* Semaphore adapter class. */
class SemaphoreAdapter : public os::Semaphore {
public:
SemaphoreAdapter(int c, int mc) : os::Semaphore(c, mc) { /* ... */ }
bool try_lock() {
return this->TryAcquire();
}
void unlock() {
this->Release();
}
};
/* Other utility. */
Result EnsureDirectoryExistsRecursively(fs::fsa::IFileSystem *fs, const char *path);
template<typename F>
NX_INLINE Result RetryFinitelyForTargetLocked(F f) {
/* Retry up to 10 times, 100ms between retries. */
constexpr s32 MaxRetryCount = 10;
constexpr u64 RetryWaitTime = 100'000'000ul;
s32 remaining_retries = MaxRetryCount;
while (true) {
R_TRY_CATCH(f()) {
R_CATCH(fs::ResultTargetLocked) {
R_UNLESS(remaining_retries > 0, fs::ResultTargetLocked());
remaining_retries--;
svcSleepThread(RetryWaitTime);
continue;
}
} R_END_TRY_CATCH;
return ResultSuccess();
}
}
}

View File

@@ -0,0 +1,194 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../../fs/fs_common.hpp"
#include "../../fs/fsa/fs_ifile.hpp"
#include "../../fs/fsa/fs_idirectory.hpp"
#include "../../fs/fsa/fs_ifilesystem.hpp"
namespace ams::fssystem::impl {
template<typename Impl>
class IPathResolutionFileSystem : public fs::fsa::IFileSystem {
NON_COPYABLE(IPathResolutionFileSystem);
private:
std::shared_ptr<fs::fsa::IFileSystem> shared_fs;
std::unique_ptr<fs::fsa::IFileSystem> unique_fs;
bool unc_preserved;
protected:
fs::fsa::IFileSystem * const base_fs;
public:
IPathResolutionFileSystem(std::shared_ptr<fs::fsa::IFileSystem> fs, bool unc = false) : shared_fs(std::move(fs)), unc_preserved(unc), base_fs(shared_fs.get()) {
/* ... */
}
IPathResolutionFileSystem(std::unique_ptr<fs::fsa::IFileSystem> fs, bool unc = false) : unique_fs(std::move(fs)), unc_preserved(unc), base_fs(unique_fs.get()) {
/* ... */
}
virtual ~IPathResolutionFileSystem() { /* ... */ }
protected:
constexpr inline bool IsUncPreserved() const {
return this->unc_preserved;
}
public:
virtual Result CreateFileImpl(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));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->CreateFile(full_path, size, option);
}
virtual Result DeleteFileImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->DeleteFile(full_path);
}
virtual Result CreateDirectoryImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->CreateDirectory(full_path);
}
virtual Result DeleteDirectoryImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->DeleteDirectory(full_path);
}
virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->DeleteDirectoryRecursively(full_path);
}
virtual Result RenameFileImpl(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));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->RenameFile(old_full_path, new_full_path);
}
virtual Result RenameDirectoryImpl(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));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->RenameDirectory(old_full_path, new_full_path);
}
virtual Result GetEntryTypeImpl(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));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->GetEntryType(out, full_path);
}
virtual Result OpenFileImpl(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));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->OpenFile(out_file, full_path, mode);
}
virtual Result OpenDirectoryImpl(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));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->OpenDirectory(out_dir, full_path, mode);
}
virtual Result CommitImpl() override {
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->Commit();
}
virtual Result GetFreeSpaceSizeImpl(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));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->GetFreeSpaceSize(out, full_path);
}
virtual Result GetTotalSpaceSizeImpl(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));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->GetTotalSpaceSize(out, full_path);
}
virtual Result CleanDirectoryRecursivelyImpl(const char *path) override {
char full_path[fs::EntryNameLengthMax + 1];
R_TRY(static_cast<Impl*>(this)->ResolveFullPath(full_path, sizeof(full_path), path));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->CleanDirectoryRecursively(full_path);
}
virtual Result GetFileTimeStampRawImpl(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));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->GetFileTimeStampRaw(out, full_path);
}
virtual Result QueryEntryImpl(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));
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->QueryEntry(dst, dst_size, src, src_size, query, full_path);
}
/* These aren't accessible as commands. */
virtual Result CommitProvisionallyImpl(s64 counter) override {
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->CommitProvisionally(counter);
}
virtual Result RollbackImpl() override {
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->Rollback();
}
virtual Result FlushImpl() override {
std::optional optional_lock = static_cast<Impl*>(this)->GetAccessorLock();
return this->base_fs->Flush();
}
};
}