diff --git a/libstratosphere/include/stratosphere/fs.hpp b/libstratosphere/include/stratosphere/fs.hpp index 1ed06212..fe2fc2ac 100644 --- a/libstratosphere/include/stratosphere/fs.hpp +++ b/libstratosphere/include/stratosphere/fs.hpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/libstratosphere/include/stratosphere/fs/fs_filesystem_utils.hpp b/libstratosphere/include/stratosphere/fs/fs_filesystem_utils.hpp new file mode 100644 index 00000000..5460dead --- /dev/null +++ b/libstratosphere/include/stratosphere/fs/fs_filesystem_utils.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#pragma once +#include "fs_common.hpp" +#include "fs_filesystem.hpp" + +namespace ams::fs { + + /* Common utilities. */ + Result EnsureDirectoryRecursively(const char *path); + Result EnsureParentDirectoryRecursively(const char *path); + + Result HasFile(bool *out, const char *path); + Result HasDirectory(bool *out, const char *path); + +} diff --git a/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp b/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp index ce71ebc9..2e9a8b48 100644 --- a/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp +++ b/libstratosphere/include/stratosphere/fssystem/fssystem_utility.hpp @@ -142,7 +142,8 @@ namespace ams::fssystem { }; /* Other utility. */ - Result EnsureDirectoryExistsRecursively(fs::fsa::IFileSystem *fs, const char *path); + Result EnsureDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path); + Result EnsureParentDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path); template NX_INLINE Result RetryFinitelyForTargetLocked(F f) { diff --git a/libstratosphere/source/fs/fs_filesystem_utils.cpp b/libstratosphere/source/fs/fs_filesystem_utils.cpp new file mode 100644 index 00000000..04b60e12 --- /dev/null +++ b/libstratosphere/source/fs/fs_filesystem_utils.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2018-2020 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 . + */ +#include +#include "fsa/fs_mount_utils.hpp" +#include "fsa/fs_filesystem_accessor.hpp" + +namespace ams::fs { + + namespace { + + Result HasEntry(bool *out, const char *path, fs::DirectoryEntryType type) { + /* Set out to false initially. */ + *out = false; + + /* Try to get the entry type. */ + fs::DirectoryEntryType entry_type; + R_TRY_CATCH(fs::GetEntryType(std::addressof(entry_type), path)) { + /* If the path doesn't exist, nothing has gone wrong. */ + R_CONVERT(fs::ResultPathNotFound, ResultSuccess()); + } R_END_TRY_CATCH; + + /* We succeeded. */ + *out = entry_type == type; + return ResultSuccess(); + } + + } + + Result EnsureDirectoryRecursively(const char *path) { + /* Get the filesystem accessor and sub path. */ + impl::FileSystemAccessor *accessor; + const char *sub_path; + R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); + + /* Use the system implementation. */ + return fssystem::EnsureDirectoryRecursively(accessor->GetRawFileSystemUnsafe(), sub_path); + } + + Result EnsureParentDirectoryRecursively(const char *path) { + /* Get the filesystem accessor and sub path. */ + impl::FileSystemAccessor *accessor; + const char *sub_path; + R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path)); + + /* Use the system implementation. */ + return fssystem::EnsureParentDirectoryRecursively(accessor->GetRawFileSystemUnsafe(), sub_path); + } + + Result HasFile(bool *out, const char *path) { + return HasEntry(out, path, fs::DirectoryEntryType_File); + } + + Result HasDirectory(bool *out, const char *path) { + return HasEntry(out, path, fs::DirectoryEntryType_Directory); + } + +} diff --git a/libstratosphere/source/fs/fsa/fs_filesystem_accessor.hpp b/libstratosphere/source/fs/fsa/fs_filesystem_accessor.hpp index 958d8cd7..5302af4a 100644 --- a/libstratosphere/source/fs/fsa/fs_filesystem_accessor.hpp +++ b/libstratosphere/source/fs/fsa/fs_filesystem_accessor.hpp @@ -86,6 +86,10 @@ namespace ams::fs::impl { } std::shared_ptr GetMultiCommitTarget(); + + fsa::IFileSystem *GetRawFileSystemUnsafe() { + return this->impl.get(); + } private: void NotifyCloseFile(FileAccessor *f); void NotifyCloseDirectory(DirectoryAccessor *d); diff --git a/libstratosphere/source/fssystem/fssystem_utility.cpp b/libstratosphere/source/fssystem/fssystem_utility.cpp index da2dde88..3612875f 100644 --- a/libstratosphere/source/fssystem/fssystem_utility.cpp +++ b/libstratosphere/source/fssystem/fssystem_utility.cpp @@ -19,7 +19,7 @@ namespace ams::fssystem { namespace { - inline Result EnsureDirectoryExists(fs::fsa::IFileSystem *fs, const char *path) { + 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; @@ -27,6 +27,30 @@ namespace ams::fssystem { return ResultSuccess(); } + 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(PathTool::Normalize(normalized_path, &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 (PathTool::IsSeparator(normalized_path[i])) { + normalized_path[i] = StringTraits::NullTerminator; + R_TRY(EnsureDirectory(fs, normalized_path)); + normalized_path[i] = StringTraits::DirectorySeparator; + } + } + + /* Create the last directory if requested. */ + if (create_last) { + R_TRY(EnsureDirectory(fs, normalized_path)); + } + + return ResultSuccess(); + } + } 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) { @@ -93,26 +117,12 @@ namespace ams::fssystem { ); } - Result EnsureDirectoryExistsRecursively(fs::fsa::IFileSystem *fs, const char *path) { - /* Normalize the path. */ - char normalized_path[fs::EntryNameLengthMax + 1]; - size_t normalized_path_len; - R_TRY(PathTool::Normalize(normalized_path, &normalized_path_len, path, sizeof(normalized_path))); + Result EnsureDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path) { + return EnsureDirectoryRecursivelyImpl(fs, path, true); + } - /* 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 (PathTool::IsSeparator(normalized_path[i])) { - normalized_path[i] = StringTraits::NullTerminator; - R_TRY(EnsureDirectoryExists(fs, normalized_path)); - normalized_path[i] = StringTraits::DirectorySeparator; - } - } - - /* Call CreateDirectory on the final path. */ - R_TRY(EnsureDirectoryExists(fs, normalized_path)); - - return ResultSuccess(); + Result EnsureParentDirectoryRecursively(fs::fsa::IFileSystem *fs, const char *path) { + return EnsureDirectoryRecursivelyImpl(fs, path, false); } } diff --git a/libstratosphere/source/ncm/ncm_content_manager_impl.cpp b/libstratosphere/source/ncm/ncm_content_manager_impl.cpp index d9d35d7a..d6ab4eae 100644 --- a/libstratosphere/source/ncm/ncm_content_manager_impl.cpp +++ b/libstratosphere/source/ncm/ncm_content_manager_impl.cpp @@ -260,7 +260,7 @@ namespace ams::ncm { ON_SCOPE_EXIT { fs::Unmount(root->mount_name); }; /* Ensure the path exists for us to import to. */ - R_TRY(impl::EnsureDirectoryRecursively(root->path)); + R_TRY(fs::EnsureDirectoryRecursively(root->path)); /* Copy the file from bis to our save. */ R_TRY(impl::CopyFile(savedata_db_path, bis_db_path)); @@ -389,7 +389,7 @@ namespace ams::ncm { ON_SCOPE_EXIT { fs::Unmount(root->mount_name); }; /* Ensure the content storage root's path exists. */ - R_TRY(impl::EnsureDirectoryRecursively(root->path)); + R_TRY(fs::EnsureDirectoryRecursively(root->path)); /* Initialize content and placeholder directories for the root. */ return ContentStorageImpl::InitializeBase(root->path); @@ -409,7 +409,7 @@ namespace ams::ncm { ON_SCOPE_EXIT { fs::Unmount(root->mount_name); }; /* Ensure the content meta database root's path exists. */ - R_TRY(impl::EnsureDirectoryRecursively(root->path)); + R_TRY(fs::EnsureDirectoryRecursively(root->path)); /* Commit our changes. */ return fs::CommitSaveData(root->mount_name); @@ -454,7 +454,7 @@ namespace ams::ncm { /* Ensure the root path exists. */ bool has_dir = false; - R_TRY(impl::HasDirectory(&has_dir, root->path)); + R_TRY(fs::HasDirectory(&has_dir, root->path)); R_UNLESS(has_dir, ncm::ResultInvalidContentMetaDatabase()); return ResultSuccess(); diff --git a/libstratosphere/source/ncm/ncm_content_storage_impl.cpp b/libstratosphere/source/ncm/ncm_content_storage_impl.cpp index 8c4bfe11..8b820c2a 100644 --- a/libstratosphere/source/ncm/ncm_content_storage_impl.cpp +++ b/libstratosphere/source/ncm/ncm_content_storage_impl.cpp @@ -36,7 +36,7 @@ namespace ams::ncm { Result EnsureContentDirectory(ContentId id, MakeContentPathFunction func, const char *root_path) { PathString path; MakeContentPath(std::addressof(path), id, func, root_path); - return impl::EnsureParentDirectoryRecursively(path); + return fs::EnsureParentDirectoryRecursively(path); } Result DeleteContentFile(ContentId id, MakeContentPathFunction func, const char *root_path) { @@ -175,11 +175,11 @@ namespace ams::ncm { /* Create the content directory. */ MakeBaseContentDirectoryPath(std::addressof(path), root_path); - R_TRY(impl::EnsureDirectoryRecursively(path)); + R_TRY(fs::EnsureDirectoryRecursively(path)); /* Create the placeholder directory. */ PlaceHolderAccessor::MakeBaseDirectoryPath(std::addressof(path), root_path); - return impl::EnsureDirectoryRecursively(path); + return fs::EnsureDirectoryRecursively(path); } Result ContentStorageImpl::CleanupBase(const char *root_path) { @@ -199,18 +199,18 @@ namespace ams::ncm { /* Check if root directory exists. */ bool has_dir; - R_TRY(impl::HasDirectory(std::addressof(has_dir), root_path)); + R_TRY(fs::HasDirectory(std::addressof(has_dir), root_path)); R_UNLESS(has_dir, ncm::ResultContentStorageBaseNotFound()); /* Check if content directory exists. */ bool has_registered; MakeBaseContentDirectoryPath(std::addressof(path), root_path); - R_TRY(impl::HasDirectory(std::addressof(has_registered), path)); + R_TRY(fs::HasDirectory(std::addressof(has_registered), path)); /* Check if placeholder directory exists. */ bool has_placeholder; PlaceHolderAccessor::MakeBaseDirectoryPath(std::addressof(path), root_path); - R_TRY(impl::HasDirectory(std::addressof(has_placeholder), path)); + R_TRY(fs::HasDirectory(std::addressof(has_placeholder), path)); /* Convert findings to results. */ R_UNLESS(has_registered || has_placeholder, ncm::ResultContentStorageBaseNotFound()); @@ -287,7 +287,7 @@ namespace ams::ncm { /* Check if placeholder file exists. */ bool has = false; - R_TRY(impl::HasFile(&has, placeholder_path)); + R_TRY(fs::HasFile(&has, placeholder_path)); out.SetValue(has); return ResultSuccess(); } @@ -335,7 +335,7 @@ namespace ams::ncm { /* Check if the content file exists. */ bool has = false; - R_TRY(impl::HasFile(&has, content_path)); + R_TRY(fs::HasFile(&has, content_path)); out.SetValue(has); return ResultSuccess(); } diff --git a/libstratosphere/source/ncm/ncm_fs_utils.cpp b/libstratosphere/source/ncm/ncm_fs_utils.cpp index 56881b55..f7369868 100644 --- a/libstratosphere/source/ncm/ncm_fs_utils.cpp +++ b/libstratosphere/source/ncm/ncm_fs_utils.cpp @@ -20,78 +20,10 @@ namespace ams::ncm::impl { namespace { - Result EnsureDirectory(const char *path) { - /* Create the path, and allow it to already exist. */ - R_TRY_CATCH(fs::CreateDirectory(path)) { - R_CONVERT(fs::ResultPathAlreadyExists, ResultSuccess()) - } R_END_TRY_CATCH; - - return ResultSuccess(); - } - - Result EnsureDirectoryRecursivelyImpl(const char *path, bool create_last) { - char work_buf[fs::EntryNameLengthMax]; - - /* Ensure the path is not too long. */ - const size_t len = std::strlen(path); - R_UNLESS(len + 1 <= sizeof(work_buf), ResultAllocationFailed()); - - /* Copy in the path. */ - std::strncpy(work_buf, path, sizeof(work_buf)); - - /* Create all but the last directory. */ - for (size_t i = 0; i < len; i++) { - if (i > 0 && fs::PathTool::IsSeparator(work_buf[i]) && !fs::PathTool::IsDriveSeparator(work_buf[i-1])) { - work_buf[i] = fs::StringTraits::NullTerminator; - R_TRY(EnsureDirectory(work_buf)); - work_buf[i] = fs::StringTraits::DirectorySeparator; - } - } - - /* Create the last directory if requested. */ - if (create_last) { - R_TRY(EnsureDirectory(path)); - } - - return ResultSuccess(); - } - - Result HasEntry(bool *out, const char *path, fs::DirectoryEntryType type) { - /* Set out to false initially. */ - *out = false; - - /* Try to get the entry type. */ - fs::DirectoryEntryType entry_type; - R_TRY_CATCH(fs::GetEntryType(std::addressof(entry_type), path)) { - /* If the path doesn't exist, nothing has gone wrong. */ - R_CONVERT(fs::ResultPathNotFound, ResultSuccess()); - } R_END_TRY_CATCH; - - /* We succeeded. */ - *out = entry_type == type; - return ResultSuccess(); - } - std::atomic g_mount_name_count; } - Result HasFile(bool *out, const char *path) { - return HasEntry(out, path, fs::DirectoryEntryType_File); - } - - Result HasDirectory(bool *out, const char *path) { - return HasEntry(out, path, fs::DirectoryEntryType_Directory); - } - - Result EnsureDirectoryRecursively(const char *path) { - return EnsureDirectoryRecursivelyImpl(path, true); - } - - Result EnsureParentDirectoryRecursively(const char *path) { - return EnsureDirectoryRecursivelyImpl(path, false); - } - bool PathView::HasPrefix(std::string_view prefix) const { return this->path.compare(0, prefix.length(), prefix) == 0; } diff --git a/libstratosphere/source/ncm/ncm_fs_utils.hpp b/libstratosphere/source/ncm/ncm_fs_utils.hpp index 438b2bde..d6c4dbf2 100644 --- a/libstratosphere/source/ncm/ncm_fs_utils.hpp +++ b/libstratosphere/source/ncm/ncm_fs_utils.hpp @@ -18,12 +18,6 @@ namespace ams::ncm::impl { - Result HasFile(bool *out, const char *path); - Result HasDirectory(bool *out, const char *path); - - Result EnsureDirectoryRecursively(const char *path); - Result EnsureParentDirectoryRecursively(const char *path); - Result CopyFile(const char *dst_path, const char *src_path); class PathView { diff --git a/libstratosphere/source/ncm/ncm_placeholder_accessor.cpp b/libstratosphere/source/ncm/ncm_placeholder_accessor.cpp index e1677117..9ed26456 100644 --- a/libstratosphere/source/ncm/ncm_placeholder_accessor.cpp +++ b/libstratosphere/source/ncm/ncm_placeholder_accessor.cpp @@ -59,7 +59,7 @@ namespace ams::ncm { Result PlaceHolderAccessor::EnsurePlaceHolderDirectory(PlaceHolderId placeholder_id) { PathString path; this->MakePath(std::addressof(path), placeholder_id); - return impl::EnsureParentDirectoryRecursively(path); + return fs::EnsureParentDirectoryRecursively(path); } Result PlaceHolderAccessor::GetPlaceHolderIdFromFileName(PlaceHolderId *out, const char *name) { diff --git a/libstratosphere/source/ncm/ncm_read_only_content_storage_impl.cpp b/libstratosphere/source/ncm/ncm_read_only_content_storage_impl.cpp index c5450540..11dbadf2 100644 --- a/libstratosphere/source/ncm/ncm_read_only_content_storage_impl.cpp +++ b/libstratosphere/source/ncm/ncm_read_only_content_storage_impl.cpp @@ -97,12 +97,12 @@ namespace ams::ncm { /* Check if the file exists. */ bool has; - R_TRY(impl::HasFile(std::addressof(has), content_path)); + R_TRY(fs::HasFile(std::addressof(has), content_path)); /* If the file is absent, make the path for game card content meta and check presence again. */ if (!has) { MakeGameCardContentMetaPath(std::addressof(content_path), content_id, this->make_content_path_func, this->root_path); - R_TRY(impl::HasFile(std::addressof(has), content_path)); + R_TRY(fs::HasFile(std::addressof(has), content_path)); } out.SetValue(has); @@ -118,7 +118,7 @@ namespace ams::ncm { /* Check if the file exists. */ bool has_file; - R_TRY(impl::HasFile(std::addressof(has_file), content_path)); + R_TRY(fs::HasFile(std::addressof(has_file), content_path)); /* If the file is absent, make the path for regular content. */ if (!has_file) {