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

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

View File

@@ -0,0 +1,124 @@
/*
* 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/fs_path.hpp>
namespace ams::fs {
class DirectoryPathParser {
NON_COPYABLE(DirectoryPathParser);
NON_MOVEABLE(DirectoryPathParser);
private:
char *m_buffer;
char m_replaced_char;
s32 m_position;
fs::Path m_current_path;
public:
DirectoryPathParser() : m_buffer(nullptr), m_replaced_char(StringTraits::NullTerminator), m_position(0), m_current_path() { /* ... */ }
const fs::Path &GetCurrentPath() const {
return m_current_path;
}
Result Initialize(fs::Path *path) {
/* Declare a default buffer, in case the path has no write buffer. */
static constinit char EmptyBuffer[1] = "";
/* Get a usable buffer. */
char *buf = path->GetWriteBufferLength() > 0 ? path->GetWriteBuffer() : EmptyBuffer;
/* Get the windows skip length. */
const auto windows_skip_len = fs::GetWindowsSkipLength(buf);
/* Set our buffer. */
m_buffer = buf + windows_skip_len;
/* Set up our initial state. */
if (windows_skip_len) {
R_TRY(m_current_path.InitializeWithNormalization(buf, windows_skip_len + 1));
} else {
if (char * const first = this->ReadNextImpl(); first != nullptr) {
R_TRY(m_current_path.InitializeWithNormalization(first));
}
}
R_SUCCEED();
}
Result ReadNext(bool *out_finished) {
/* Default to not finished. */
*out_finished = false;
/* Get the next child component. */
if (auto * const child = this->ReadNextImpl(); child != nullptr) {
/* Append the child component to our current path. */
R_TRY(m_current_path.AppendChild(child));
} else {
/* We have no child component, so we're finished. */
*out_finished = true;
}
R_SUCCEED();
}
private:
char *ReadNextImpl() {
/* Check that we have characters to read. */
if (m_position < 0 || m_buffer[0] == StringTraits::NullTerminator) {
return nullptr;
}
/* If we have a replaced character, restore it. */
if (m_replaced_char != StringTraits::NullTerminator) {
m_buffer[m_position] = m_replaced_char;
if (m_replaced_char == StringTraits::DirectorySeparator) {
++m_position;
}
}
/* If we're at the start of a root-relative path, begin by returning the root. */
if (m_position == 0 && m_buffer[0] == StringTraits::DirectorySeparator) {
m_replaced_char = m_buffer[1];
m_buffer[1] = StringTraits::NullTerminator;
m_position = 1;
return m_buffer;
}
/* Otherwise, find the end of the next path component. */
s32 i;
for (i = m_position; m_buffer[i] != StringTraits::DirectorySeparator; ++i) {
if (m_buffer[i] == StringTraits::NullTerminator) {
if (i == m_position) {
m_position = -1;
return nullptr;
}
}
}
/* Sanity check that we're not ending on a separator. */
AMS_ASSERT(m_buffer[i + 1] != StringTraits::NullTerminator);
char * const ret = m_buffer + m_position;
m_replaced_char = StringTraits::DirectorySeparator;
m_buffer[i] = 0;
m_position = i;
return ret;
}
};
}

View File

@@ -82,7 +82,7 @@ namespace ams::fs {
public:
constexpr FileStorageBasedFileSystem() : FileStorage(), m_base_file_system(nullptr) { /* ... */ }
Result Initialize(std::shared_ptr<fs::fsa::IFileSystem> base_file_system, const char *path, fs::OpenMode mode);
Result Initialize(std::shared_ptr<fs::fsa::IFileSystem> base_file_system, const fs::Path &path, fs::OpenMode mode);
};
class FileHandleStorage : public IStorage, public impl::Newable {

View File

@@ -20,7 +20,13 @@ namespace ams::fs {
constexpr inline size_t EntryNameLengthMax = 0x300;
using DirectoryEntry = ::FsDirectoryEntry;
struct DirectoryEntry {
char name[EntryNameLengthMax + 1];
char pad[3];
s8 type;
u8 pad2[3];
s64 file_size;
};
struct DirectoryHandle {
void *handle;

View File

@@ -24,7 +24,11 @@ namespace ams::fs {
static const ReadOption None;
};
inline constexpr const ReadOption ReadOption::None = {FsReadOption_None};
enum ReadOptionFlag : u32 {
ReadOptionFlag_None = (0 << 0),
};
inline constexpr const ReadOption ReadOption::None = {ReadOptionFlag_None};
inline constexpr bool operator==(const ReadOption &lhs, const ReadOption &rhs) {
return lhs._value == rhs._value;
@@ -36,19 +40,24 @@ namespace ams::fs {
static_assert(util::is_pod<ReadOption>::value && sizeof(ReadOption) == sizeof(u32));
enum WriteOptionFlag : u32 {
WriteOptionFlag_None = (0 << 0),
WriteOptionFlag_Flush = (1 << 0),
};
struct WriteOption {
u32 _value;
constexpr inline bool HasFlushFlag() const {
return _value & FsWriteOption_Flush;
return _value & WriteOptionFlag_Flush;
}
static const WriteOption None;
static const WriteOption Flush;
};
inline constexpr const WriteOption WriteOption::None = {FsWriteOption_None};
inline constexpr const WriteOption WriteOption::Flush = {FsWriteOption_Flush};
inline constexpr const WriteOption WriteOption::None = {WriteOptionFlag_None};
inline constexpr const WriteOption WriteOption::Flush = {WriteOptionFlag_Flush};
inline constexpr bool operator==(const WriteOption &lhs, const WriteOption &rhs) {
return lhs._value == rhs._value;

View File

@@ -25,8 +25,8 @@ namespace ams::fs {
}
enum OpenMode {
OpenMode_Read = (1 << 0),
OpenMode_Write = (1 << 1),
OpenMode_Read = (1 << 0),
OpenMode_Write = (1 << 1),
OpenMode_AllowAppend = (1 << 2),
OpenMode_ReadWrite = (OpenMode_Read | OpenMode_Write),
@@ -34,23 +34,23 @@ namespace ams::fs {
};
enum OpenDirectoryMode {
OpenDirectoryMode_Directory = ::FsDirOpenMode_ReadDirs,
OpenDirectoryMode_File = ::FsDirOpenMode_ReadFiles,
OpenDirectoryMode_Directory = (1 << 0),
OpenDirectoryMode_File = (1 << 1),
OpenDirectoryMode_All = (OpenDirectoryMode_Directory | OpenDirectoryMode_File),
/* TODO: Separate enum, like N? */
OpenDirectoryMode_NotRequireFileSize = ::FsDirOpenMode_NoFileSize,
OpenDirectoryMode_NotRequireFileSize = (1 << 31),
};
enum DirectoryEntryType {
DirectoryEntryType_Directory = ::FsDirEntryType_Dir,
DirectoryEntryType_File = ::FsDirEntryType_File,
DirectoryEntryType_Directory = 0,
DirectoryEntryType_File = 1,
};
enum CreateOption {
CreateOption_None = 0,
CreateOption_BigFile = ::FsCreateOption_BigFile,
CreateOption_None = (0 << 0),
CreateOption_BigFile = (1 << 0),
};
struct FileHandle;

View File

@@ -16,10 +16,37 @@
#pragma once
#include <stratosphere/fs/fs_common.hpp>
#include <stratosphere/fs/fs_filesystem.hpp>
#include <stratosphere/time/time_posix_time.hpp>
namespace ams::fs {
using FileTimeStampRaw = ::FsTimeStampRaw;
struct FileTimeStamp {
time::PosixTime create;
time::PosixTime modify;
time::PosixTime access;
bool is_local_time;
char pad[7];
};
static_assert(util::is_pod<FileTimeStamp>::value && sizeof(FileTimeStamp) == 0x20);
struct FileTimeStampRaw {
s64 create;
s64 modify;
s64 access;
bool is_local_time;
char pad[7];
};
static_assert(util::is_pod<FileTimeStampRaw>::value && sizeof(FileTimeStampRaw) == 0x20);
static_assert(__builtin_offsetof(FileTimeStampRaw, create) == __builtin_offsetof(FileTimeStampRaw, create));
static_assert(__builtin_offsetof(FileTimeStampRaw, modify) == __builtin_offsetof(FileTimeStampRaw, modify));
static_assert(__builtin_offsetof(FileTimeStampRaw, access) == __builtin_offsetof(FileTimeStampRaw, access));
static_assert(__builtin_offsetof(FileTimeStampRaw, is_local_time) == __builtin_offsetof(FileTimeStampRaw, is_local_time));
static_assert(__builtin_offsetof(FileTimeStampRaw, pad) == __builtin_offsetof(FileTimeStampRaw, pad));
#if defined(ATMOSPHERE_OS_HORIZON)
static_assert(sizeof(FileTimeStampRaw) == sizeof(::FsTimeStampRaw));
#endif
namespace impl {
@@ -27,6 +54,6 @@ namespace ams::fs {
}
Result GetFileTimeStampRawForDebug(FileTimeStampRaw *out, const char *path);
Result GetFileTimeStamp(FileTimeStamp *out, const char *path);
}

View File

@@ -21,8 +21,8 @@
namespace ams::fs {
/* Common utilities. */
Result EnsureDirectoryRecursively(const char *path);
Result EnsureParentDirectoryRecursively(const char *path);
Result EnsureDirectory(const char *path);
Result EnsureParentDirectory(const char *path);
Result HasFile(bool *out, const char *path);
Result HasDirectory(bool *out, const char *path);

View File

@@ -0,0 +1,58 @@
/*
* 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/ncm/ncm_ids.hpp>
#include <stratosphere/fs/fs_code_verification_data.hpp>
namespace ams::fs {
enum MountHostOptionFlag : u32 {
MountHostOptionFlag_None = (0 << 0),
MountHostOptionFlag_PseudoCaseSensitive = (1 << 0),
};
struct MountHostOption {
u32 _value;
constexpr inline bool HasPseudoCaseSensitiveFlag() const {
return _value & MountHostOptionFlag_PseudoCaseSensitive;
}
static const MountHostOption None;
static const MountHostOption PseudoCaseSensitive;
};
inline constexpr const MountHostOption MountHostOption::None = {MountHostOptionFlag_None};
inline constexpr const MountHostOption MountHostOption::PseudoCaseSensitive = {MountHostOptionFlag_PseudoCaseSensitive};
inline constexpr bool operator==(const MountHostOption &lhs, const MountHostOption &rhs) {
return lhs._value == rhs._value;
}
inline constexpr bool operator!=(const MountHostOption &lhs, const MountHostOption &rhs) {
return !(lhs == rhs);
}
Result MountHost(const char *name, const char *root_path);
Result MountHost(const char *name, const char *root_path, const MountHostOption &option);
Result MountHostRoot();
Result MountHostRoot(const MountHostOption &option);
void UnmountHostRoot();
}

View File

@@ -68,13 +68,13 @@ namespace ams::fs {
std::unique_ptr<IStorage> m_unique_storage;
IStorage *m_storage;
public:
ReadOnlyStorageAdapter(IStorage *s) : m_unique_storage(s) {
explicit ReadOnlyStorageAdapter(IStorage *s) : m_unique_storage(s) {
m_storage = m_unique_storage.get();
}
ReadOnlyStorageAdapter(std::shared_ptr<IStorage> s) : m_shared_storage(s) {
explicit ReadOnlyStorageAdapter(std::shared_ptr<IStorage> s) : m_shared_storage(s) {
m_storage = m_shared_storage.get();
}
ReadOnlyStorageAdapter(std::unique_ptr<IStorage> s) : m_unique_storage(std::move(s)) {
explicit ReadOnlyStorageAdapter(std::unique_ptr<IStorage> s) : m_unique_storage(std::move(s)) {
m_storage = m_unique_storage.get();
}

View File

@@ -0,0 +1,582 @@
/*
* 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/fs_memory_management.hpp>
#include <stratosphere/fs/impl/fs_common_mount_name.hpp>
#include <stratosphere/fs/fs_path_utility.hpp>
namespace ams::fs {
class DirectoryPathParser;
class Path {
NON_COPYABLE(Path);
NON_MOVEABLE(Path);
private:
static constexpr const char *EmptyPath = "";
static constexpr size_t WriteBufferAlignmentLength = 8;
private:
friend class DirectoryPathParser;
private:
using WriteBuffer = std::unique_ptr<char[], ::ams::fs::impl::Deleter>;
private:
const char *m_str;
util::TypedStorage<WriteBuffer> m_write_buffer;
size_t m_write_buffer_length;
bool m_is_normalized;
public:
Path() : m_str(EmptyPath), m_write_buffer_length(0), m_is_normalized(false) {
util::ConstructAt(m_write_buffer, nullptr);
}
constexpr Path(const char *s, util::ConstantInitializeTag) : m_str(s), m_write_buffer(), m_write_buffer_length(0), m_is_normalized(true) {
/* ... */
}
constexpr ~Path() {
if (!std::is_constant_evaluated()) {
util::DestroyAt(m_write_buffer);
}
}
WriteBuffer ReleaseBuffer() {
/* Check pre-conditions. */
AMS_ASSERT(util::GetReference(m_write_buffer) != nullptr);
/* Reset. */
m_str = EmptyPath;
m_write_buffer_length = 0;
/* Return our write buffer. */
return std::move(util::GetReference(m_write_buffer));
}
constexpr Result SetShallowBuffer(const char *buffer) {
/* Check pre-conditions. */
AMS_ASSERT(m_write_buffer_length == 0);
/* Check the buffer is valid. */
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
/* Set buffer. */
this->SetReadOnlyBuffer(buffer);
/* Note that we're normalized. */
m_is_normalized = true;
R_SUCCEED();
}
const char *GetString() const {
/* Check pre-conditions. */
AMS_ASSERT(m_is_normalized);
return m_str;
}
size_t GetLength() const {
return std::strlen(this->GetString());
}
bool IsEmpty() const {
return *m_str == '\x00';
}
bool IsMatchHead(const char *p, size_t len) const {
return util::Strncmp(this->GetString(), p, len) == 0;
}
Result Initialize(const Path &rhs) {
/* Check the other path is normalized. */
R_UNLESS(rhs.m_is_normalized, fs::ResultNotNormalized());
/* Allocate buffer for our path. */
const auto len = rhs.GetLength();
R_TRY(this->Preallocate(len + 1));
/* Copy the path. */
const size_t copied = util::Strlcpy<char>(util::GetReference(m_write_buffer).get(), rhs.GetString(), len + 1);
R_UNLESS(copied == len, fs::ResultUnexpectedInPathA());
/* Set normalized. */
m_is_normalized = rhs.m_is_normalized;
R_SUCCEED();
}
Result Initialize(const char *path, size_t len) {
/* Check the path is valid. */
R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
/* Initialize. */
R_TRY(this->InitializeImpl(path, len));
/* Set not normalized. */
m_is_normalized = false;
R_SUCCEED();
}
Result Initialize(const char *path) {
/* Check the path is valid. */
R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
return this->Initialize(path, std::strlen(path));
}
Result InitializeWithFormat(const char *fmt, ...) __attribute__((format (printf, 2, 3))) {
/* Check the format string is valid. */
R_UNLESS(fmt != nullptr, fs::ResultNullptrArgument());
/* Create the va_list for formatting. */
std::va_list vl;
va_start(vl, fmt);
/* Determine how big the string will be. */
char dummy;
const auto len = util::VSNPrintf(std::addressof(dummy), 0, fmt, vl);
/* Allocate buffer for our path. */
R_TRY(this->Preallocate(len + 1));
/* Format our path into our new buffer. */
const auto real_len = util::VSNPrintf(util::GetReference(m_write_buffer).get(), m_write_buffer_length, fmt, vl);
AMS_ASSERT(real_len == len);
AMS_UNUSED(real_len);
/* Finish the va_list. */
va_end(vl);
/* Set not normalized. */
m_is_normalized = false;
R_SUCCEED();
}
Result InitializeWithReplaceBackslash(const char *path) {
/* Check the path is valid. */
R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
/* Initialize. */
R_TRY(this->InitializeImpl(path, std::strlen(path)));
/* Replace slashes as desired. */
if (m_write_buffer_length > 1) {
fs::Replace(this->GetWriteBuffer(), m_write_buffer_length - 1, '\\', '/');
}
/* Set not normalized. */
m_is_normalized = false;
R_SUCCEED();
}
Result InitializeWithReplaceForwardSlashes(const char *path) {
/* Check the path is valid. */
R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
/* Initialize. */
R_TRY(this->InitializeImpl(path, std::strlen(path)));
/* Replace slashes as desired. */
if (m_write_buffer_length > 1) {
if (auto *p = this->GetWriteBuffer(); p[0] == '/' && p[1] == '/') {
p[0] = '\\';
p[1] = '\\';
}
}
/* Set not normalized. */
m_is_normalized = false;
R_SUCCEED();
}
Result InitializeWithReplaceUnc(const char *path) {
/* Check the path is valid. */
R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
/* Initialize. */
R_TRY(this->InitializeImpl(path, std::strlen(path)));
/* Set not normalized. */
m_is_normalized = false;
/* Replace unc as desired. */
if (m_str[0]) {
auto *p = this->GetWriteBuffer();
/* Replace :/// -> \\ as needed. */
if (auto *sep = std::strstr(p, ":///"); sep != nullptr) {
sep[0] = '\\';
sep[1] = '\\';
}
/* Edit path prefix. */
if (!util::Strncmp(p, AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME AMS_FS_IMPL_MOUNT_NAME_DELIMITER "/", AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN + 1)) {
static_assert((AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME AMS_FS_IMPL_MOUNT_NAME_DELIMITER)[AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN - 1] == '/');
p[AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN - 1] = '\\';
p[AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN + AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN - 0] = '\\';
}
if (p[0] == '/' && p[1] == '/') {
p[0] = '\\';
p[1] = '\\';
}
}
R_SUCCEED();
}
Result InitializeWithNormalization(const char *path, size_t size) {
/* Check the path is valid. */
R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
/* Initialize. */
R_TRY(this->InitializeImpl(path, size));
/* Set not normalized. */
m_is_normalized = false;
/* Perform normalization. */
fs::PathFlags path_flags;
if (fs::IsPathRelative(m_str)) {
path_flags.AllowRelativePath();
} else if (fs::IsWindowsPath(m_str, true)) {
path_flags.AllowWindowsPath();
} else {
/* NOTE: In this case, Nintendo checks is normalized, then sets is normalized, then returns success. */
/* This seems like a bug. */
size_t dummy;
R_TRY(PathFormatter::IsNormalized(std::addressof(m_is_normalized), std::addressof(dummy), m_str));
m_is_normalized = true;
R_SUCCEED();
}
/* Normalize. */
R_TRY(this->Normalize(path_flags));
m_is_normalized = true;
R_SUCCEED();
}
Result InitializeWithNormalization(const char *path) {
/* Check the path is valid. */
R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
R_RETURN(this->InitializeWithNormalization(path, std::strlen(path)));
}
Result InitializeAsEmpty() {
/* Clear our buffer. */
this->ClearBuffer();
/* Set normalized. */
m_is_normalized = true;
R_SUCCEED();
}
Result AppendChild(const char *child) {
/* Check the path is valid. */
R_UNLESS(child != nullptr, fs::ResultNullptrArgument());
/* Basic checks. If we hvea a path and the child is empty, we have nothing to do. */
const char *c = child;
if (m_str[0]) {
/* Skip an early separator. */
if (*c == '/') {
++c;
}
R_SUCCEED_IF(*c == '\x00');
}
/* If we don't have a string, we can just initialize. */
auto cur_len = std::strlen(m_str);
if (cur_len == 0) {
R_RETURN(this->Initialize(child));
}
/* Remove a trailing separator. */
if (m_str[cur_len - 1] == '/' || m_str[cur_len - 1] == '\\') {
--cur_len;
}
/* Get the child path's length. */
auto child_len = std::strlen(c);
/* Reset our write buffer. */
WriteBuffer old_write_buffer;
if (util::GetReference(m_write_buffer) != nullptr) {
old_write_buffer = std::move(util::GetReference(m_write_buffer));
this->ClearBuffer();
}
/* Pre-allocate the new buffer. */
R_TRY(this->Preallocate(cur_len + 1 + child_len + 1));
/* Get our write buffer. */
auto *dst = this->GetWriteBuffer();
if (old_write_buffer != nullptr && cur_len > 0) {
util::Strlcpy<char>(dst, old_write_buffer.get(), cur_len + 1);
}
/* Add separator. */
dst[cur_len] = '/';
/* Copy the child path. */
const size_t copied = util::Strlcpy<char>(dst + cur_len + 1, c, child_len + 1);
R_UNLESS(copied == child_len, fs::ResultUnexpectedInPathA());
R_SUCCEED();
}
Result AppendChild(const Path &rhs) {
R_RETURN(this->AppendChild(rhs.GetString()));
}
Result Combine(const Path &parent, const Path &child) {
/* Get the lengths. */
const auto p_len = parent.GetLength();
const auto c_len = child.GetLength();
/* Allocate our buffer. */
R_TRY(this->Preallocate(p_len + c_len + 1));
/* Initialize as parent. */
R_TRY(this->Initialize(parent));
/* If we're empty, we can just initialize as child. */
if (this->IsEmpty()) {
R_TRY(this->Initialize(child));
} else {
/* Otherwise, we should append the child. */
R_TRY(this->AppendChild(child));
}
R_SUCCEED();
}
Result RemoveChild() {
/* If we don't have a write-buffer, ensure that we have one. */
if (util::GetReference(m_write_buffer) == nullptr) {
if (const auto len = std::strlen(m_str); len > 0) {
R_TRY(this->Preallocate(len));
util::Strlcpy<char>(util::GetReference(m_write_buffer).get(), m_str, len + 1);
}
}
/* Check that it's possible for us to remove a child. */
auto *p = this->GetWriteBuffer();
s32 len = std::strlen(p);
R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), fs::ResultNotImplemented());
/* Handle a trailing separator. */
if (len > 0 && (p[len - 1] == '\\' || p[len - 1] == '/')) {
--len;
}
/* Remove the child path segment. */
while ((--len) >= 0 && p[len]) {
if (p[len] == '/' || p[len] == '\\') {
if (len > 0) {
p[len] = 0;
} else {
p[1] = 0;
len = 1;
}
break;
}
}
/* Check that length remains > 0. */
R_UNLESS(len > 0, fs::ResultNotImplemented());
R_SUCCEED();
}
Result Normalize(const PathFlags &flags) {
/* If we're already normalized, nothing to do. */
R_SUCCEED_IF(m_is_normalized);
/* Check if we're normalized. */
bool normalized;
size_t dummy;
R_TRY(PathFormatter::IsNormalized(std::addressof(normalized), std::addressof(dummy), m_str, flags));
/* If we're not normalized, normalize. */
if (!normalized) {
/* Determine necessary buffer length. */
auto len = m_write_buffer_length;
if (flags.IsRelativePathAllowed() && fs::IsPathRelative(m_str)) {
len += 2;
}
if (flags.IsWindowsPathAllowed() && fs::IsWindowsPath(m_str, true)) {
len += 1;
}
/* Allocate a new buffer. */
const size_t size = util::AlignUp(len, WriteBufferAlignmentLength);
auto buf = fs::impl::MakeUnique<char[]>(size);
R_UNLESS(buf != nullptr, fs::ResultAllocationFailureInMakeUnique());
/* Normalize into it. */
R_TRY(PathFormatter::Normalize(buf.get(), size, util::GetReference(m_write_buffer).get(), m_write_buffer_length, flags));
/* Set the normalized buffer as our buffer. */
this->SetModifiableBuffer(std::move(buf), size);
}
/* Set normalized. */
m_is_normalized = true;
R_SUCCEED();
}
private:
void ClearBuffer() {
util::GetReference(m_write_buffer).reset();
m_write_buffer_length = 0;
m_str = EmptyPath;
}
void SetModifiableBuffer(WriteBuffer &&buffer, size_t size) {
/* Check pre-conditions. */
AMS_ASSERT(buffer.get() != nullptr);
AMS_ASSERT(size > 0);
AMS_ASSERT(util::IsAligned(size, WriteBufferAlignmentLength));
/* Set write buffer. */
util::GetReference(m_write_buffer) = std::move(buffer);
m_write_buffer_length = size;
m_str = util::GetReference(m_write_buffer).get();
}
constexpr void SetReadOnlyBuffer(const char *buffer) {
m_str = buffer;
if (!std::is_constant_evaluated()) {
util::GetReference(m_write_buffer) = nullptr;
m_write_buffer_length = 0;
}
}
Result Preallocate(size_t length) {
/* Allocate additional space, if needed. */
if (length > m_write_buffer_length) {
/* Allocate buffer. */
const size_t size = util::AlignUp(length, WriteBufferAlignmentLength);
auto buf = fs::impl::MakeUnique<char[]>(size);
R_UNLESS(buf != nullptr, fs::ResultAllocationFailureInMakeUnique());
/* Set write buffer. */
this->SetModifiableBuffer(std::move(buf), size);
}
R_SUCCEED();
}
Result InitializeImpl(const char *path, size_t size) {
if (size > 0 && path[0]) {
/* Pre allocate a buffer for the path. */
R_TRY(this->Preallocate(size + 1));
/* Copy the path. */
const size_t copied = util::Strlcpy<char>(this->GetWriteBuffer(), path, size + 1);
R_UNLESS(copied >= size, fs::ResultUnexpectedInPathA());
} else {
/* We can just clear the buffer. */
this->ClearBuffer();
}
R_SUCCEED();
}
char *GetWriteBuffer() {
AMS_ASSERT(util::GetReference(m_write_buffer) != nullptr);
return util::GetReference(m_write_buffer).get();
}
size_t GetWriteBufferLength() const {
return m_write_buffer_length;
}
public:
ALWAYS_INLINE bool operator==(const fs::Path &rhs) const { return std::strcmp(this->GetString(), rhs.GetString()) == 0; }
ALWAYS_INLINE bool operator!=(const fs::Path &rhs) const { return !(*this == rhs); }
ALWAYS_INLINE bool operator==(const char *p) const { return std::strcmp(this->GetString(), p) == 0; }
ALWAYS_INLINE bool operator!=(const char *p) const { return !(*this == p); }
};
consteval fs::Path MakeConstantPath(const char *s) { return fs::Path(s, util::ConstantInitializeTag{}); }
inline Result SetUpFixedPath(fs::Path *out, const char *s) {
/* Verify the path is normalized. */
bool normalized;
size_t dummy;
R_TRY(PathNormalizer::IsNormalized(std::addressof(normalized), std::addressof(dummy), s));
R_UNLESS(normalized, fs::ResultInvalidPathFormat());
/* Set the fixed path. */
R_RETURN(out->SetShallowBuffer(s));
}
inline Result SetUpFixedPathSingleEntry(fs::Path *out, char *buf, size_t buf_size, const char *e) {
/* Print the path into the buffer. */
const size_t len = util::TSNPrintf(buf, buf_size, "/%s", e);
R_UNLESS(len < buf_size, fs::ResultInvalidArgument());
/* Set up the path. */
R_RETURN(SetUpFixedPath(out, buf));
}
inline Result SetUpFixedPathDoubleEntry(fs::Path *out, char *buf, size_t buf_size, const char *e, const char *e2) {
/* Print the path into the buffer. */
const size_t len = util::TSNPrintf(buf, buf_size, "/%s/%s", e, e2);
R_UNLESS(len < buf_size, fs::ResultInvalidArgument());
/* Set up the path. */
R_RETURN(SetUpFixedPath(out, buf));
}
inline Result SetUpFixedPathSaveId(fs::Path *out, char *buf, size_t buf_size, u64 id) {
/* Print the path into the buffer. */
const size_t len = util::TSNPrintf(buf, buf_size, "/%016" PRIx64 "", id);
R_UNLESS(len < buf_size, fs::ResultInvalidArgument());
/* Set up the path. */
R_RETURN(SetUpFixedPath(out, buf));
}
inline Result SetUpFixedPathSaveMetaName(fs::Path *out, char *buf, size_t buf_size, u32 type) {
/* Print the path into the buffer. */
const size_t len = util::TSNPrintf(buf, buf_size, "/%08" PRIx32 ".meta", type);
R_UNLESS(len < buf_size, fs::ResultInvalidArgument());
/* Set up the path. */
R_RETURN(SetUpFixedPath(out, buf));
}
inline Result SetUpFixedPathSaveMetaDir(fs::Path *out, char *buf, size_t buf_size, u64 id) {
/* Print the path into the buffer. */
const size_t len = util::TSNPrintf(buf, buf_size, "/saveMeta/%016" PRIx64 "", id);
R_UNLESS(len < buf_size, fs::ResultInvalidArgument());
/* Set up the path. */
R_RETURN(SetUpFixedPath(out, buf));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,123 +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/fssrv/sf/fssrv_sf_path.hpp>
namespace ams::fs {
namespace StringTraits {
constexpr inline char DirectorySeparator = '/';
constexpr inline char DriveSeparator = ':';
constexpr inline char Dot = '.';
constexpr inline char NullTerminator = '\x00';
constexpr inline char AlternateDirectorySeparator = '\\';
}
/* Windows path utilities. */
constexpr inline bool IsWindowsDrive(const char *path) {
AMS_ASSERT(path != nullptr);
const char c = path[0];
return (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) && path[1] == StringTraits::DriveSeparator;
}
constexpr inline bool IsUnc(const char *path) {
return (path[0] == StringTraits::DirectorySeparator && path[1] == StringTraits::DirectorySeparator) ||
(path[0] == StringTraits::AlternateDirectorySeparator && path[1] == StringTraits::AlternateDirectorySeparator);
}
constexpr inline s64 GetWindowsPathSkipLength(const char *path) {
if (IsWindowsDrive(path)) {
return 2;
}
if (IsUnc(path)) {
for (s64 i = 2; path[i] != StringTraits::NullTerminator; ++i) {
if (path[i] == '$' || path[i] == ':') {
return i + 1;
}
}
}
return 0;
}
/* Path utilities. */
inline void Replace(char *dst, size_t dst_size, char old_char, char new_char) {
AMS_ASSERT(dst != nullptr);
for (char *cur = dst; cur < dst + dst_size && *cur != StringTraits::NullTerminator; ++cur) {
if (*cur == old_char) {
*cur = new_char;
}
}
}
Result FspPathPrintf(fssrv::sf::FspPath *dst, const char *format, ...) __attribute__((format(printf, 2, 3)));
inline Result FspPathPrintf(fssrv::sf::FspPath *dst, const char *format, ...) {
AMS_ASSERT(dst != nullptr);
/* Format the path. */
std::va_list va_list;
va_start(va_list, format);
const size_t len = util::VSNPrintf(dst->str, sizeof(dst->str), format, va_list);
va_end(va_list);
/* Validate length. */
R_UNLESS(len < sizeof(dst->str), fs::ResultTooLongPath());
/* Fix slashes. */
Replace(dst->str, sizeof(dst->str) - 1, '\\', '/');
return ResultSuccess();
}
Result VerifyPath(const char *path, int max_path_len, int max_name_len);
bool IsSubPath(const char *lhs, const char *rhs);
/* Path normalization. */
class PathNormalizer {
public:
static constexpr const char RootPath[] = "/";
public:
static constexpr inline bool IsSeparator(char c) {
return c == StringTraits::DirectorySeparator;
}
static constexpr inline bool IsAnySeparator(char c) {
return c == StringTraits::DirectorySeparator || c == StringTraits::AlternateDirectorySeparator;
}
static constexpr inline bool IsNullTerminator(char c) {
return c == StringTraits::NullTerminator;
}
static constexpr inline bool IsCurrentDirectory(const char *p) {
return p[0] == StringTraits::Dot && (IsSeparator(p[1]) || IsNullTerminator(p[1]));
}
static constexpr inline bool IsParentDirectory(const char *p) {
return p[0] == StringTraits::Dot && p[1] == StringTraits::Dot && (IsSeparator(p[2]) || IsNullTerminator(p[2]));
}
static Result Normalize(char *out, size_t *out_len, const char *src, size_t max_out_size, bool unc_preserved = false, bool has_mount_name = false);
static Result IsNormalized(bool *out, const char *path, bool unc_preserved = false, bool has_mount_name = false);
};
}

View File

@@ -38,7 +38,10 @@ namespace ams::fs {
static_assert(util::is_pod<QueryRangeInfo>::value);
static_assert(sizeof(QueryRangeInfo) == 0x40);
#if defined(ATMOSPHERE_OS_HORIZON)
static_assert(sizeof(QueryRangeInfo) == sizeof(::FsRangeInfo));
#endif
using FileQueryRangeInfo = QueryRangeInfo;
using StorageQueryRangeInfo = QueryRangeInfo;

View File

@@ -30,7 +30,7 @@ namespace ams::fs {
private:
std::unique_ptr<fsa::IFile> m_base_file;
public:
explicit ReadOnlyFile(std::unique_ptr<fsa::IFile> &&f) : m_base_file(std::move(f)) { /* ... */ }
explicit ReadOnlyFile(std::unique_ptr<fsa::IFile> &&f) : m_base_file(std::move(f)) { AMS_ASSERT(m_base_file != nullptr); }
virtual ~ReadOnlyFile() { /* ... */ }
private:
virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final {
@@ -46,12 +46,17 @@ namespace ams::fs {
}
virtual Result DoWrite(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final {
AMS_UNUSED(offset, buffer, size, option);
bool need_append;
R_TRY(this->DryWrite(std::addressof(need_append), offset, size, option, fs::OpenMode_Read));
AMS_ASSERT(!need_append);
AMS_UNUSED(buffer);
return fs::ResultUnsupportedOperationInReadOnlyFileA();
}
virtual Result DoSetSize(s64 size) override final {
AMS_UNUSED(size);
R_TRY(this->DrySetSize(size, fs::OpenMode_Read));
return fs::ResultUnsupportedOperationInReadOnlyFileA();
}
@@ -82,7 +87,7 @@ namespace ams::fs {
explicit ReadOnlyFileSystemTemplate(T &&fs) : m_base_fs(std::move(fs)) { /* ... */ }
virtual ~ReadOnlyFileSystemTemplate() { /* ... */ }
private:
virtual Result DoOpenFile(std::unique_ptr<fsa::IFile> *out_file, const char *path, OpenMode mode) override final {
virtual Result DoOpenFile(std::unique_ptr<fsa::IFile> *out_file, const fs::Path &path, OpenMode mode) override final {
/* Only allow opening files with mode = read. */
R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidOpenMode());
@@ -96,11 +101,11 @@ namespace ams::fs {
return ResultSuccess();
}
virtual Result DoOpenDirectory(std::unique_ptr<fsa::IDirectory> *out_dir, const char *path, OpenDirectoryMode mode) override final {
virtual Result DoOpenDirectory(std::unique_ptr<fsa::IDirectory> *out_dir, const fs::Path &path, OpenDirectoryMode mode) override final {
return m_base_fs->OpenDirectory(out_dir, path, mode);
}
virtual Result DoGetEntryType(DirectoryEntryType *out, const char *path) override final {
virtual Result DoGetEntryType(DirectoryEntryType *out, const fs::Path &path) override final {
return m_base_fs->GetEntryType(out, path);
}
@@ -108,52 +113,52 @@ namespace ams::fs {
return ResultSuccess();
}
virtual Result DoCreateFile(const char *path, s64 size, int flags) override final {
virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override final {
AMS_UNUSED(path, size, flags);
return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA();
}
virtual Result DoDeleteFile(const char *path) override final {
virtual Result DoDeleteFile(const fs::Path &path) override final {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA();
}
virtual Result DoCreateDirectory(const char *path) override final {
virtual Result DoCreateDirectory(const fs::Path &path) override final {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA();
}
virtual Result DoDeleteDirectory(const char *path) override final {
virtual Result DoDeleteDirectory(const fs::Path &path) override final {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA();
}
virtual Result DoDeleteDirectoryRecursively(const char *path) override final {
virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override final {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA();
}
virtual Result DoRenameFile(const char *old_path, const char *new_path) override final {
virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override final {
AMS_UNUSED(old_path, new_path);
return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA();
}
virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override final {
virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override final {
AMS_UNUSED(old_path, new_path);
return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA();
}
virtual Result DoCleanDirectoryRecursively(const char *path) override final {
virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override final {
AMS_UNUSED(path);
return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateA();
}
virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override final {
virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override final {
AMS_UNUSED(out, path);
return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateB();
}
virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override final {
virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override final {
AMS_UNUSED(out, path);
return fs::ResultUnsupportedOperationInReadOnlyFileSystemTemplateB();
}

View File

@@ -20,11 +20,13 @@
#include <stratosphere/fs/fsa/fs_idirectory.hpp>
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
#include <stratosphere/fs/fs_query_range.hpp>
#include <stratosphere/fs/fs_path_utils.hpp>
namespace ams::fs {
#if defined(ATMOSPHERE_OS_HORIZON)
class RemoteFile : public fsa::IFile, public impl::Newable {
NON_COPYABLE(RemoteFile);
NON_MOVEABLE(RemoteFile);
private:
::FsFile m_base_file;
public:
@@ -67,6 +69,8 @@ namespace ams::fs {
};
class RemoteDirectory : public fsa::IDirectory, public impl::Newable {
NON_COPYABLE(RemoteDirectory);
NON_MOVEABLE(RemoteDirectory);
private:
::FsDir m_base_dir;
public:
@@ -75,7 +79,8 @@ namespace ams::fs {
virtual ~RemoteDirectory() { fsDirClose(std::addressof(m_base_dir)); }
public:
virtual Result DoRead(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override final {
return fsDirRead(std::addressof(m_base_dir), out_count, max_entries, out_entries);
static_assert(sizeof(*out_entries) == sizeof(::FsDirectoryEntry));
return fsDirRead(std::addressof(m_base_dir), out_count, max_entries, reinterpret_cast<::FsDirectoryEntry *>(out_entries));
}
virtual Result DoGetEntryCount(s64 *out) override final {
@@ -88,6 +93,8 @@ namespace ams::fs {
};
class RemoteFileSystem : public fsa::IFileSystem, public impl::Newable {
NON_COPYABLE(RemoteFileSystem);
NON_MOVEABLE(RemoteFileSystem);
private:
::FsFileSystem m_base_fs;
public:
@@ -95,52 +102,51 @@ namespace ams::fs {
virtual ~RemoteFileSystem() { fsFsClose(std::addressof(m_base_fs)); }
private:
Result GetPathForServiceObject(fssrv::sf::Path *out_path, const char *path) {
/* Copy and null terminate. */
std::strncpy(out_path->str, path, sizeof(out_path->str) - 1);
out_path->str[sizeof(out_path->str) - 1] = '\x00';
Result GetPathForServiceObject(fssrv::sf::Path *out_path, const fs::Path &path) {
/* Copy, ensuring length is in bounds. */
const size_t len = util::Strlcpy<char>(out_path->str, path.GetString(), sizeof(out_path->str));
R_UNLESS(len < sizeof(out_path->str), fs::ResultTooLongPath());
/* Replace directory separators. */
fs::Replace(out_path->str, sizeof(out_path->str) - 1, StringTraits::AlternateDirectorySeparator, StringTraits::DirectorySeparator);
/* TODO: Is this still necessary? We originally had it to not break things on low firmware. */
#if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
fs::Replace(out_path->str, sizeof(out_path->str) - 1, '\\', '/');
#endif
/* Get lengths. */
const auto skip_len = fs::GetWindowsPathSkipLength(path);
const auto rel_path = out_path->str + skip_len;
const auto max_len = fs::EntryNameLengthMax - skip_len;
return VerifyPath(rel_path, max_len, max_len);
R_SUCCEED();
}
public:
virtual Result DoCreateFile(const char *path, s64 size, int flags) override final {
virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override final {
fssrv::sf::Path sf_path;
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
return fsFsCreateFile(std::addressof(m_base_fs), sf_path.str, size, flags);
}
virtual Result DoDeleteFile(const char *path) override final {
virtual Result DoDeleteFile(const fs::Path &path) override final {
fssrv::sf::Path sf_path;
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
return fsFsDeleteFile(std::addressof(m_base_fs), sf_path.str);
}
virtual Result DoCreateDirectory(const char *path) override final {
virtual Result DoCreateDirectory(const fs::Path &path) override final {
fssrv::sf::Path sf_path;
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
return fsFsCreateDirectory(std::addressof(m_base_fs), sf_path.str);
}
virtual Result DoDeleteDirectory(const char *path) override final {
virtual Result DoDeleteDirectory(const fs::Path &path) override final {
fssrv::sf::Path sf_path;
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
return fsFsDeleteDirectory(std::addressof(m_base_fs), sf_path.str);
}
virtual Result DoDeleteDirectoryRecursively(const char *path) override final {
virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override final {
fssrv::sf::Path sf_path;
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
return fsFsDeleteDirectoryRecursively(std::addressof(m_base_fs), sf_path.str);
}
virtual Result DoRenameFile(const char *old_path, const char *new_path) override final {
virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override final {
fssrv::sf::Path old_sf_path;
fssrv::sf::Path new_sf_path;
R_TRY(GetPathForServiceObject(std::addressof(old_sf_path), old_path));
@@ -148,7 +154,7 @@ namespace ams::fs {
return fsFsRenameFile(std::addressof(m_base_fs), old_sf_path.str, new_sf_path.str);
}
virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override final {
virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override final {
fssrv::sf::Path old_sf_path;
fssrv::sf::Path new_sf_path;
R_TRY(GetPathForServiceObject(std::addressof(old_sf_path), old_path));
@@ -156,7 +162,7 @@ namespace ams::fs {
return fsFsRenameDirectory(std::addressof(m_base_fs), old_sf_path.str, new_sf_path.str);
}
virtual Result DoGetEntryType(DirectoryEntryType *out, const char *path) override final {
virtual Result DoGetEntryType(DirectoryEntryType *out, const fs::Path &path) override final {
fssrv::sf::Path sf_path;
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
@@ -164,7 +170,7 @@ namespace ams::fs {
return fsFsGetEntryType(std::addressof(m_base_fs), sf_path.str, reinterpret_cast<::FsDirEntryType *>(out));
}
virtual Result DoOpenFile(std::unique_ptr<fsa::IFile> *out_file, const char *path, OpenMode mode) override final {
virtual Result DoOpenFile(std::unique_ptr<fsa::IFile> *out_file, const fs::Path &path, OpenMode mode) override final {
fssrv::sf::Path sf_path;
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
@@ -178,7 +184,7 @@ namespace ams::fs {
return ResultSuccess();
}
virtual Result DoOpenDirectory(std::unique_ptr<fsa::IDirectory> *out_dir, const char *path, OpenDirectoryMode mode) override final {
virtual Result DoOpenDirectory(std::unique_ptr<fsa::IDirectory> *out_dir, const fs::Path &path, OpenDirectoryMode mode) override final {
fssrv::sf::Path sf_path;
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
@@ -196,37 +202,37 @@ namespace ams::fs {
return fsFsCommit(std::addressof(m_base_fs));
}
virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) {
virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) {
fssrv::sf::Path sf_path;
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
return fsFsGetFreeSpace(std::addressof(m_base_fs), sf_path.str, out);
}
virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) {
virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) {
fssrv::sf::Path sf_path;
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
return fsFsGetTotalSpace(std::addressof(m_base_fs), sf_path.str, out);
}
virtual Result DoCleanDirectoryRecursively(const char *path) {
virtual Result DoCleanDirectoryRecursively(const fs::Path &path) {
fssrv::sf::Path sf_path;
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
return fsFsCleanDirectoryRecursively(std::addressof(m_base_fs), sf_path.str);
}
virtual Result DoGetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) {
virtual Result DoGetFileTimeStampRaw(FileTimeStampRaw *out, const fs::Path &path) {
fssrv::sf::Path sf_path;
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
static_assert(sizeof(FileTimeStampRaw) == sizeof(::FsTimeStampRaw));
return fsFsGetFileTimeStampRaw(std::addressof(m_base_fs), sf_path.str, reinterpret_cast<::FsTimeStampRaw *>(out));
}
virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path) {
virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const fs::Path &path) {
fssrv::sf::Path sf_path;
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
return fsFsQueryEntry(std::addressof(m_base_fs), dst, dst_size, src, src_size, sf_path.str, static_cast<FsFileSystemQueryId>(query));
}
};
#endif
}

View File

@@ -20,35 +20,35 @@
namespace ams::fs {
#if defined(ATMOSPHERE_OS_HORIZON)
class RemoteStorage : public IStorage, public impl::Newable {
NON_COPYABLE(RemoteStorage);
NON_MOVEABLE(RemoteStorage);
private:
std::unique_ptr<::FsStorage, impl::Deleter> m_base_storage;
::FsStorage m_base_storage;
public:
RemoteStorage(::FsStorage &s) {
m_base_storage = impl::MakeUnique<::FsStorage>();
*m_base_storage = s;
}
RemoteStorage(::FsStorage &s) : m_base_storage(s) { /* ... */}
virtual ~RemoteStorage() { fsStorageClose(m_base_storage.get()); }
virtual ~RemoteStorage() { fsStorageClose(std::addressof(m_base_storage)); }
public:
virtual Result Read(s64 offset, void *buffer, size_t size) override {
return fsStorageRead(m_base_storage.get(), offset, buffer, size);
return fsStorageRead(std::addressof(m_base_storage), offset, buffer, size);
};
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
return fsStorageWrite(m_base_storage.get(), offset, buffer, size);
return fsStorageWrite(std::addressof(m_base_storage), offset, buffer, size);
};
virtual Result Flush() override {
return fsStorageFlush(m_base_storage.get());
return fsStorageFlush(std::addressof(m_base_storage));
};
virtual Result GetSize(s64 *out_size) override {
return fsStorageGetSize(m_base_storage.get(), out_size);
return fsStorageGetSize(std::addressof(m_base_storage), out_size);
};
virtual Result SetSize(s64 size) override {
return fsStorageSetSize(m_base_storage.get(), size);
return fsStorageSetSize(std::addressof(m_base_storage), size);
};
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
@@ -57,5 +57,6 @@ namespace ams::fs {
return fs::ResultUnsupportedOperation();
};
};
#endif
}

View File

@@ -51,20 +51,20 @@ namespace ams::fs {
RomFileTable *GetRomFileTable();
Result GetFileBaseOffset(s64 *out, const char *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 DoGetTotalSpaceSize(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 DoGetTotalSpaceSize(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;

View File

@@ -82,6 +82,20 @@ namespace ams::fs {
SaveDataFlags_NeedsSecureDelete = (1 << 3),
};
enum class SaveDataMetaType : u8 {
None = 0,
Thumbnail = 1,
ExtensionContext = 2,
};
struct SaveDataMetaInfo {
u32 size;
SaveDataMetaType type;
u8 reserved[0xB];
};
static_assert(util::is_pod<SaveDataMetaInfo>::value);
static_assert(sizeof(SaveDataMetaInfo) == 0x10);
struct SaveDataCreationInfo {
s64 size;
s64 journal_size;

View File

@@ -20,6 +20,12 @@ namespace ams::fs {
class IEventNotifier;
struct EncryptionSeed {
char value[0x10];
};
static_assert(util::is_pod<EncryptionSeed>::value);
static_assert(sizeof(EncryptionSeed) == 0x10);
Result MountSdCard(const char *name);
Result MountSdCardErrorReportDirectoryForAtmosphere(const char *name);

View File

@@ -30,20 +30,20 @@ namespace ams::fs {
public:
SharedFileSystemHolder(std::shared_ptr<fsa::IFileSystem> f) : m_fs(std::move(f)) { /* ... */ }
public:
virtual Result DoCreateFile(const char *path, s64 size, int flags) override { return m_fs->CreateFile(path, size, flags); }
virtual Result DoDeleteFile(const char *path) override { return m_fs->DeleteFile(path); }
virtual Result DoCreateDirectory(const char *path) override { return m_fs->CreateDirectory(path); }
virtual Result DoDeleteDirectory(const char *path) override { return m_fs->DeleteDirectory(path); }
virtual Result DoDeleteDirectoryRecursively(const char *path) override { return m_fs->DeleteDirectoryRecursively(path); }
virtual Result DoRenameFile(const char *old_path, const char *new_path) override { return m_fs->RenameFile(old_path, new_path); }
virtual Result DoRenameDirectory(const char *old_path, const char *new_path) override { return m_fs->RenameDirectory(old_path, new_path); }
virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) override { return m_fs->GetEntryType(out, path); }
virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) override { return m_fs->OpenFile(out_file, path, mode); }
virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) override { return m_fs->OpenDirectory(out_dir, path, mode); }
virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) override { return m_fs->CreateFile(path, size, flags); }
virtual Result DoDeleteFile(const fs::Path &path) override { return m_fs->DeleteFile(path); }
virtual Result DoCreateDirectory(const fs::Path &path) override { return m_fs->CreateDirectory(path); }
virtual Result DoDeleteDirectory(const fs::Path &path) override { return m_fs->DeleteDirectory(path); }
virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) override { return m_fs->DeleteDirectoryRecursively(path); }
virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) override { return m_fs->RenameFile(old_path, new_path); }
virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) override { return m_fs->RenameDirectory(old_path, new_path); }
virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) override { return m_fs->GetEntryType(out, path); }
virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) override { return m_fs->OpenFile(out_file, path, mode); }
virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) override { return m_fs->OpenDirectory(out_dir, path, mode); }
virtual Result DoCommit() override { return m_fs->Commit(); }
virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) override { return m_fs->GetFreeSpaceSize(out, path); }
virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) override { return m_fs->GetTotalSpaceSize(out, path); }
virtual Result DoCleanDirectoryRecursively(const char *path) override { return m_fs->CleanDirectoryRecursively(path); }
virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) override { return m_fs->GetFreeSpaceSize(out, path); }
virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) override { return m_fs->GetTotalSpaceSize(out, path); }
virtual Result DoCleanDirectoryRecursively(const fs::Path &path) override { return m_fs->CleanDirectoryRecursively(path); }
/* These aren't accessible as commands. */
virtual Result DoCommitProvisionally(s64 counter) override { return m_fs->CommitProvisionally(counter); }

View File

@@ -31,13 +31,13 @@ namespace ams::fs::fsa {
return ResultSuccess();
}
R_UNLESS(out_entries != nullptr, fs::ResultNullptrArgument());
R_UNLESS(max_entries > 0, fs::ResultInvalidArgument());
return this->DoRead(out_count, out_entries, max_entries);
R_UNLESS(max_entries > 0, fs::ResultInvalidArgument());
R_RETURN(this->DoRead(out_count, out_entries, max_entries));
}
Result GetEntryCount(s64 *out) {
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->DoGetEntryCount(out);
R_RETURN(this->DoGetEntryCount(out));
}
public:
/* TODO: This is a hack to allow the mitm API to work. Find a better way? */

View File

@@ -26,58 +26,69 @@ namespace ams::fs::fsa {
virtual ~IFile() { /* ... */ }
Result Read(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) {
/* Check that we have an output pointer. */
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
/* If we have nothing to read, just succeed. */
if (size == 0) {
*out = 0;
return ResultSuccess();
R_SUCCEED();
}
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
R_UNLESS(offset >= 0, fs::ResultOutOfRange());
/* Check that the read is valid. */
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
R_UNLESS(offset >= 0, fs::ResultOutOfRange());
R_UNLESS(util::IsIntValueRepresentable<s64>(size), fs::ResultOutOfRange());
const s64 signed_size = static_cast<s64>(size);
R_UNLESS(signed_size >= 0, fs::ResultOutOfRange());
R_UNLESS((std::numeric_limits<s64>::max() - offset) >= signed_size, fs::ResultOutOfRange());
return this->DoRead(out, offset, buffer, size, option);
/* Do the read. */
R_RETURN(this->DoRead(out, offset, buffer, size, option));
}
Result Read(size_t *out, s64 offset, void *buffer, size_t size) {
return this->Read(out, offset, buffer, size, ReadOption::None);
}
ALWAYS_INLINE Result Read(size_t *out, s64 offset, void *buffer, size_t size) { R_RETURN(this->Read(out, offset, buffer, size, ReadOption::None)); }
Result GetSize(s64 *out) {
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->DoGetSize(out);
R_RETURN(this->DoGetSize(out));
}
Result Flush() {
return this->DoFlush();
R_RETURN(this->DoFlush());
}
Result Write(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) {
/* Handle the zero-size case. */
if (size == 0) {
if (option.HasFlushFlag()) {
R_TRY(this->Flush());
}
return ResultSuccess();
R_SUCCEED();
}
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
R_UNLESS(offset >= 0, fs::ResultOutOfRange());
/* Check the write is valid. */
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
R_UNLESS(offset >= 0, fs::ResultOutOfRange());
R_UNLESS(util::IsIntValueRepresentable<s64>(size), fs::ResultOutOfRange());
const s64 signed_size = static_cast<s64>(size);
R_UNLESS(signed_size >= 0, fs::ResultOutOfRange());
R_UNLESS((std::numeric_limits<s64>::max() - offset) >= signed_size, fs::ResultOutOfRange());
return this->DoWrite(offset, buffer, size, option);
R_RETURN(this->DoWrite(offset, buffer, size, option));
}
Result SetSize(s64 size) {
R_UNLESS(size >= 0, fs::ResultOutOfRange());
return this->DoSetSize(size);
R_RETURN(this->DoSetSize(size));
}
Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
return this->DoOperateRange(dst, dst_size, op_id, offset, size, src, src_size);
R_RETURN(this->DoOperateRange(dst, dst_size, op_id, offset, size, src, src_size));
}
Result OperateRange(fs::OperationId op_id, s64 offset, s64 size) {
return this->DoOperateRange(nullptr, 0, op_id, offset, size, nullptr, 0);
R_RETURN(this->DoOperateRange(nullptr, 0, op_id, offset, size, nullptr, 0));
}
public:
/* TODO: This is a hack to allow the mitm API to work. Find a better way? */
@@ -91,21 +102,19 @@ namespace ams::fs::fsa {
/* Get the file size, and validate our offset. */
s64 file_size = 0;
R_TRY(this->GetSize(&file_size));
R_TRY(this->DoGetSize(std::addressof(file_size)));
R_UNLESS(offset <= file_size, fs::ResultOutOfRange());
*out = static_cast<size_t>(std::min(file_size - offset, static_cast<s64>(size)));
return ResultSuccess();
R_SUCCEED();
}
Result DrySetSize(s64 size, fs::OpenMode open_mode) {
/* Check that we can write. */
R_UNLESS((open_mode & OpenMode_Write) != 0, fs::ResultWriteNotPermitted());
AMS_ASSERT(size >= 0);
AMS_UNUSED(size);
return ResultSuccess();
/* Check that we can write. */
R_UNLESS((open_mode & OpenMode_Write) != 0, fs::ResultWriteNotPermitted());
R_SUCCEED();
}
Result DryWrite(bool *out_append, s64 offset, size_t size, const fs::WriteOption &option, fs::OpenMode open_mode) {
@@ -116,17 +125,16 @@ namespace ams::fs::fsa {
/* Get the file size. */
s64 file_size = 0;
R_TRY(this->GetSize(&file_size));
R_TRY(this->DoGetSize(&file_size));
/* Determine if we need to append. */
if (file_size < offset + static_cast<s64>(size)) {
*out_append = false;
if (file_size < offset + static_cast<s64>(size)) {
R_UNLESS((open_mode & OpenMode_AllowAppend) != 0, fs::ResultFileExtensionWithoutOpenModeAllowAppend());
*out_append = true;
} else {
*out_append = false;
}
return ResultSuccess();
R_SUCCEED();
}
private:
virtual Result DoRead(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) = 0;

View File

@@ -18,6 +18,7 @@
#include <stratosphere/fs/fs_common.hpp>
#include <stratosphere/fs/fs_filesystem.hpp>
#include <stratosphere/fs/fs_filesystem_for_debug.hpp>
#include <stratosphere/fs/fs_path.hpp>
namespace ams::fs::fsa {
@@ -26,172 +27,156 @@ namespace ams::fs::fsa {
enum class QueryId {
SetConcatenationFileAttribute = 0,
UpdateMac = 1,
IsSignedSystemPartitionOnSdCardValid = 2,
QueryUnpreparedFileInformation = 3,
};
class IFileSystem {
public:
virtual ~IFileSystem() { /* ... */ }
Result CreateFile(const char *path, s64 size, int option) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(size >= 0, fs::ResultOutOfRange());
return this->DoCreateFile(path, size, option);
Result CreateFile(const fs::Path &path, s64 size, int option) {
R_UNLESS(size >= 0, fs::ResultOutOfRange());
R_RETURN(this->DoCreateFile(path, size, option));
}
Result CreateFile(const char *path, s64 size) {
return this->CreateFile(path, size, 0);
Result CreateFile(const fs::Path &path, s64 size) {
R_RETURN(this->CreateFile(path, size, fs::CreateOption_None));
}
Result DeleteFile(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->DoDeleteFile(path);
Result DeleteFile(const fs::Path &path) {
R_RETURN(this->DoDeleteFile(path));
}
Result CreateDirectory(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->DoCreateDirectory(path);
Result CreateDirectory(const fs::Path &path) {
R_RETURN(this->DoCreateDirectory(path));
}
Result DeleteDirectory(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->DoDeleteDirectory(path);
Result DeleteDirectory(const fs::Path &path) {
R_RETURN(this->DoDeleteDirectory(path));
}
Result DeleteDirectoryRecursively(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->DoDeleteDirectoryRecursively(path);
Result DeleteDirectoryRecursively(const fs::Path &path) {
R_RETURN(this->DoDeleteDirectoryRecursively(path));
}
Result RenameFile(const char *old_path, const char *new_path) {
R_UNLESS(old_path != nullptr, fs::ResultInvalidPath());
R_UNLESS(new_path != nullptr, fs::ResultInvalidPath());
return this->DoRenameFile(old_path, new_path);
Result RenameFile(const fs::Path &old_path, const fs::Path &new_path) {
R_RETURN(this->DoRenameFile(old_path, new_path));
}
Result RenameDirectory(const char *old_path, const char *new_path) {
R_UNLESS(old_path != nullptr, fs::ResultInvalidPath());
R_UNLESS(new_path != nullptr, fs::ResultInvalidPath());
return this->DoRenameDirectory(old_path, new_path);
Result RenameDirectory(const fs::Path &old_path, const fs::Path &new_path) {
R_RETURN(this->DoRenameDirectory(old_path, new_path));
}
Result GetEntryType(DirectoryEntryType *out, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->DoGetEntryType(out, path);
Result GetEntryType(DirectoryEntryType *out, const fs::Path &path) {
R_RETURN(this->DoGetEntryType(out, path));
}
Result OpenFile(std::unique_ptr<IFile> *out_file, const char *path, OpenMode mode) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
Result OpenFile(std::unique_ptr<IFile> *out_file, const fs::Path &path, OpenMode mode) {
R_UNLESS(out_file != nullptr, fs::ResultNullptrArgument());
R_UNLESS((mode & OpenMode_ReadWrite) != 0, fs::ResultInvalidOpenMode());
R_UNLESS((mode & ~OpenMode_All) == 0, fs::ResultInvalidOpenMode());
return this->DoOpenFile(out_file, path, mode);
R_RETURN(this->DoOpenFile(out_file, path, mode));
}
Result OpenDirectory(std::unique_ptr<IDirectory> *out_dir, const char *path, OpenDirectoryMode mode) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
Result OpenDirectory(std::unique_ptr<IDirectory> *out_dir, const fs::Path &path, OpenDirectoryMode mode) {
R_UNLESS(out_dir != nullptr, fs::ResultNullptrArgument());
R_UNLESS((mode & OpenDirectoryMode_All) != 0, fs::ResultInvalidOpenMode());
R_UNLESS((mode & ~(OpenDirectoryMode_All | OpenDirectoryMode_NotRequireFileSize)) == 0, fs::ResultInvalidOpenMode());
return this->DoOpenDirectory(out_dir, path, mode);
R_RETURN(this->DoOpenDirectory(out_dir, path, mode));
}
Result Commit() {
return this->DoCommit();
R_RETURN(this->DoCommit());
}
Result GetFreeSpaceSize(s64 *out, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
Result GetFreeSpaceSize(s64 *out, const fs::Path &path) {
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->DoGetFreeSpaceSize(out, path);
R_RETURN(this->DoGetFreeSpaceSize(out, path));
}
Result GetTotalSpaceSize(s64 *out, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
Result GetTotalSpaceSize(s64 *out, const fs::Path &path) {
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->DoGetTotalSpaceSize(out, path);
R_RETURN(this->DoGetTotalSpaceSize(out, path));
}
Result CleanDirectoryRecursively(const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->DoCleanDirectoryRecursively(path);
Result CleanDirectoryRecursively(const fs::Path &path) {
R_RETURN(this->DoCleanDirectoryRecursively(path));
}
Result GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
Result GetFileTimeStampRaw(FileTimeStampRaw *out, const fs::Path &path) {
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
return this->DoGetFileTimeStampRaw(out, path);
R_RETURN(this->DoGetFileTimeStampRaw(out, path));
}
Result QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, QueryId query, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
return this->DoQueryEntry(dst, dst_size, src, src_size, query, path);
Result QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, QueryId query, const fs::Path &path) {
R_RETURN(this->DoQueryEntry(dst, dst_size, src, src_size, query, path));
}
/* These aren't accessible as commands. */
Result CommitProvisionally(s64 counter) {
return this->DoCommitProvisionally(counter);
R_RETURN(this->DoCommitProvisionally(counter));
}
Result Rollback() {
return this->DoRollback();
R_RETURN(this->DoRollback());
}
Result Flush() {
return this->DoFlush();
R_RETURN(this->DoFlush());
}
protected:
/* ...? */
private:
virtual Result DoCreateFile(const char *path, s64 size, int flags) = 0;
virtual Result DoDeleteFile(const char *path) = 0;
virtual Result DoCreateDirectory(const char *path) = 0;
virtual Result DoDeleteDirectory(const char *path) = 0;
virtual Result DoDeleteDirectoryRecursively(const char *path) = 0;
virtual Result DoRenameFile(const char *old_path, const char *new_path) = 0;
virtual Result DoRenameDirectory(const char *old_path, const char *new_path) = 0;
virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const char *path) = 0;
virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) = 0;
virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) = 0;
virtual Result DoCreateFile(const fs::Path &path, s64 size, int flags) = 0;
virtual Result DoDeleteFile(const fs::Path &path) = 0;
virtual Result DoCreateDirectory(const fs::Path &path) = 0;
virtual Result DoDeleteDirectory(const fs::Path &path) = 0;
virtual Result DoDeleteDirectoryRecursively(const fs::Path &path) = 0;
virtual Result DoRenameFile(const fs::Path &old_path, const fs::Path &new_path) = 0;
virtual Result DoRenameDirectory(const fs::Path &old_path, const fs::Path &new_path) = 0;
virtual Result DoGetEntryType(fs::DirectoryEntryType *out, const fs::Path &path) = 0;
virtual Result DoOpenFile(std::unique_ptr<fs::fsa::IFile> *out_file, const fs::Path &path, fs::OpenMode mode) = 0;
virtual Result DoOpenDirectory(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const fs::Path &path, fs::OpenDirectoryMode mode) = 0;
virtual Result DoCommit() = 0;
virtual Result DoGetFreeSpaceSize(s64 *out, const char *path) {
virtual Result DoGetFreeSpaceSize(s64 *out, const fs::Path &path) {
AMS_UNUSED(out, path);
return fs::ResultNotImplemented();
R_THROW(fs::ResultNotImplemented());
}
virtual Result DoGetTotalSpaceSize(s64 *out, const char *path) {
virtual Result DoGetTotalSpaceSize(s64 *out, const fs::Path &path) {
AMS_UNUSED(out, path);
return fs::ResultNotImplemented();
R_THROW(fs::ResultNotImplemented());
}
virtual Result DoCleanDirectoryRecursively(const char *path) = 0;
virtual Result DoCleanDirectoryRecursively(const fs::Path &path) = 0;
virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const char *path) {
virtual Result DoGetFileTimeStampRaw(fs::FileTimeStampRaw *out, const fs::Path &path) {
AMS_UNUSED(out, path);
return fs::ResultNotImplemented();
R_THROW(fs::ResultNotImplemented());
}
virtual Result DoQueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fs::fsa::QueryId query, const char *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) {
AMS_UNUSED(dst, dst_size, src, src_size, query, path);
return fs::ResultNotImplemented();
R_THROW(fs::ResultNotImplemented());
}
/* These aren't accessible as commands. */
virtual Result DoCommitProvisionally(s64 counter) {
AMS_UNUSED(counter);
return fs::ResultNotImplemented();
R_THROW(fs::ResultNotImplemented());
}
virtual Result DoRollback() {
return fs::ResultNotImplemented();
R_THROW(fs::ResultNotImplemented());
}
virtual Result DoFlush() {
return fs::ResultNotImplemented();
R_THROW(fs::ResultNotImplemented());
}
};

View File

@@ -83,6 +83,8 @@ namespace ams::fs::impl {
}
}
static_assert(sizeof(size_t) == sizeof(u64));
}
/* Access log result name. */
@@ -91,19 +93,41 @@ namespace ams::fs::impl {
#define AMS_FS_IMPL_ACCESS_LOG_DEREFERENCE_OUT_VALUE(__VALUE__) ::ams::fs::impl::DereferenceOutValue(__VALUE__, AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME)
/* Access log components. */
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SIZE ", size: %" PRId64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_READ_SIZE ", read_size: %zu"
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_OFFSET_AND_SIZE ", offset: %" PRId64 ", size: %zu"
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID ", thread_id: %" PRIu64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT ", name: \"%s\""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_ENTRY_COUNT ", entry_count: %" PRId64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_ENTRY_BUFFER_COUNT ", entry_buffer_count: %" PRId64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_OPEN_MODE ", open_mode: 0x%" PRIX32 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH ", path: \"%s\""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_SIZE ", path: \"%s\", size: %" PRId64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_OPEN_MODE ", path: \"%s\", open_mode: 0x%" PRIX32 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME ", path: \"%s\", new_path: \"%s\""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_DIRECTORY_ENTRY_TYPE ", entry_type: %s"
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SIZE ", size: %" PRId64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_READ_SIZE ", read_size: %" PRIuZ ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_QUERY_SIZE ", read_size: %" PRIuZ ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_OFFSET_AND_SIZE ", offset: %" PRId64 ", size: %" PRIuZ ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_THREAD_ID ", thread_id: %" PRIu64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT ", name: \"%s\""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_ENTRY_COUNT ", entry_count: %" PRId64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_ENTRY_BUFFER_COUNT ", entry_buffer_count: %" PRId64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_OPEN_MODE ", open_mode: 0x%" PRIX32 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH ", path: \"%s\""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_SIZE ", path: \"%s\", size: %" PRId64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH_AND_OPEN_MODE ", path: \"%s\", open_mode: 0x%" PRIX32 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_RENAME ", path: \"%s\", new_path: \"%s\""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_DIRECTORY_ENTRY_TYPE ", entry_type: %s"
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE ", content_type: %s"
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_OPTION ", mount_host_option: %s"
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_ROOT_PATH ", root_path: %s"
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_APPLICATION_ID ", applicationid: 0x%" PRIx64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_BIS_PARTITION_ID ", bispartitionid: %s"
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_STORAGE_ID ", contentstorageid: %s"
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SYSTEM_DATA_ID ", systemdataid: 0x%" PRIx64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_DATA_ID ", dataid: 0x%" PRIx64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_GAME_CARD_HANDLE ", gamecard_handle: 0x%" PRIX32 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_GAME_CARD_PARTITION ", gamecard_partition: %s"
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_IMAGE_DIRECTORY_ID ", imagedirectoryid: %s"
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_PROGRAM_ID ", programid: 0x%" PRIx64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID ", savedataid: 0x%" PRIx64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID ", savedataspaceid: %s"
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_OWNER_ID ", save_data_owner_id: 0x%" PRIx64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_USER_ID ", userid: 0x%016" PRIx64 "%016" PRIx64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_FLAGS ", save_data_flags: 0x%08" PRIX32 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_JOURNAL_SIZE ", save_data_journal_size: %" PRId64 ""
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SIZE ", save_data_size: %" PRId64 ""
/* Access log formats. */
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_NONE ""
@@ -130,62 +154,135 @@ namespace ams::fs::impl {
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_GET_SPACE_SIZE(__OUT_SIZE__, __NAME__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_SIZE, __NAME__, AMS_FS_IMPL_ACCESS_LOG_DEREFERENCE_OUT_VALUE(__OUT_SIZE__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_APPLICATION_PACKAGE(__NAME__, __PATH__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, (__NAME__), (__PATH__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_BIS(__NAME__, __ID__, __PATH__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_BIS_PARTITION_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH, (__NAME__), ::ams::fs::impl::IdString().ToString(__ID__), (__PATH__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CODE(__NAME__, __PATH__, __ID__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_PROGRAM_ID, (__NAME__), (__PATH__), (__ID__).value
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH(__NAME__, __PATH__, __TYPE__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE, (__NAME__), (__PATH__), ::ams::fs::impl::IdString().ToString(__TYPE__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PROGRAM_ID(__NAME__, __ID__, __TYPE__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PROGRAM_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE, (__NAME__), (__ID__), ::ams::fs::impl::IdString().ToString(__TYPE__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH_AND_PROGRAM_ID(__NAME__, __PATH__, __ID__, __TYPE__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_PROGRAM_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE, (__NAME__), (__PATH__), (__ID__).value, ::ams::fs::impl::IdString().ToString(__TYPE__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_PATH_AND_DATA_ID(__NAME__, __PATH__, __ID__, __TYPE__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_TYPE, (__NAME__), (__PATH__), (__ID__).value, ::ams::fs::impl::IdString().ToString(__TYPE__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_CONTENT_STORAGE(__NAME__, __ID__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_CONTENT_STORAGE_ID, (__NAME__), ::ams::fs::impl::IdString().ToString(__ID__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_DEVICE_SAVE_DATA_APPLICATION_ID(__NAME__, __ID__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_APPLICATION_ID, (__NAME__), (__ID__).value
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_GAME_CARD_PARTITION(__NAME__, __GCHANDLE__, __PARTITION__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_GAME_CARD_HANDLE AMS_FS_IMPL_ACCESS_LOG_FORMAT_GAME_CARD_PARTITION, (__NAME__), __GCHANDLE__, ::ams::fs::impl::IdString().ToString(__PARTITION__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT() \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT, (AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_ROOT_WITH_OPTION(__OPTION__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_OPTION, (AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME), ::ams::fs::impl::IdString().ToString(__OPTION__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST(__NAME__, __ROOT_PATH__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_ROOT_PATH, (__NAME__), (__ROOT_PATH__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_WITH_OPTION(__NAME__, __ROOT_PATH__, __OPTION__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_ROOT_PATH AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_HOST_OPTION, (__NAME__), (__ROOT_PATH__), ::ams::fs::impl::IdString().ToString(__OPTION__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_IMAGE_DIRECTORY(__NAME__, __ID__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_IMAGE_DIRECTORY_ID, (__NAME__), ::ams::fs::impl::IdString().ToString(__ID__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_DATA(__NAME__, __ID__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_SYSTEM_DATA_ID, (__NAME__), (__ID__).value
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT_SYSTEM_SAVE_DATA(__NAME__, __SPACE__, __SAVE__, __USER__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_MOUNT AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_USER_ID, \
(__NAME__), ::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__), (__USER__).data[0], (__USER__).data[1]
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_CREATE_SYSTEM_SAVE_DATA(__SPACE__, __SAVE__, __USER__, __OWNER__, __SIZE__, __JOURNAL_SIZE__, __FLAGS__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_USER_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_OWNER_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SIZE AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_JOURNAL_SIZE AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_FLAGS, \
::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__), (__USER__).data[0], (__USER__).data[1], (__OWNER__), (__SIZE__), (__JOURNAL_SIZE__), (__FLAGS__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_DELETE_SAVE_DATA(__SPACE__, __SAVE__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID, \
::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_DELETE_SYSTEM_SAVE_DATA(__SPACE__, __SAVE__, __USER__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_USER_ID, \
::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__), (__USER__).data[0], (__USER__).data[1]
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_EXTEND_SAVE_DATA(__SPACE__, __SAVE__, __SIZE__, __JOURNAL_SIZE__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SPACE_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_SIZE AMS_FS_IMPL_ACCESS_LOG_FORMAT_SAVE_DATA_JOURNAL_SIZE, \
::ams::fs::impl::IdString().ToString(__SPACE__), (__SAVE__), (__SIZE__), (__JOURNAL_SIZE__)
#define AMS_FS_IMPL_ACCESS_LOG_FORMAT_QUERY_MOUNT_SYSTEM_DATA_CACHE_SIZE(__ID__, __SIZE__) \
AMS_FS_IMPL_ACCESS_LOG_FORMAT_SYSTEM_DATA_ID AMS_FS_IMPL_ACCESS_LOG_FORMAT_QUERY_SIZE, (__ID__).value, AMS_FS_IMPL_ACCESS_LOG_DEREFERENCE_OUT_VALUE(__SIZE__)
/* Access log invocation lambdas. */
#define AMS_FS_IMPL_ACCESS_LOG_IMPL(__EXPR__, __HANDLE__, __ENABLED__, __NAME__, ...) \
[&](const char *name) -> Result { \
if (!(__ENABLED__)) { \
return (__EXPR__); \
} else { \
const ::ams::os::Tick start = ::ams::os::GetSystemTick(); \
const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \
const ::ams::os::Tick end = ::ams::os::GetSystemTick(); \
::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, start, end, name, __HANDLE__, __VA_ARGS__); \
return AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME; \
} \
#define AMS_FS_IMPL_ACCESS_LOG_IMPL(__EXPR__, __HANDLE__, __ENABLED__, __NAME__, ...) \
[&](const char *__fs_func_name_) -> Result { \
if (!(__ENABLED__)) { \
R_RETURN(__EXPR__); \
} else { \
const ::ams::os::Tick __fs_start_tick = ::ams::os::GetSystemTick(); \
const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \
const ::ams::os::Tick __fs_end_tick = ::ams::os::GetSystemTick(); \
::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __fs_start_tick, __fs_end_tick, __fs_func_name_, __HANDLE__, __VA_ARGS__); \
R_RETURN( AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME ); \
} \
}(__NAME__)
#define AMS_FS_IMPL_ACCESS_LOG_WITH_PRIORITY_IMPL(__EXPR__, __PRIORITY__, __HANDLE__, __ENABLED__, __NAME__, ...) \
[&](const char *name) -> Result { \
if (!(__ENABLED__)) { \
return (__EXPR__); \
} else { \
const ::ams::os::Tick start = ::ams::os::GetSystemTick(); \
const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \
const ::ams::os::Tick end = ::ams::os::GetSystemTick(); \
::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __PRIORITY__, start, end, name, __HANDLE__, __VA_ARGS__); \
return AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME; \
} \
#define AMS_FS_IMPL_ACCESS_LOG_WITH_PRIORITY_IMPL(__EXPR__, __PRIORITY__, __HANDLE__, __ENABLED__, __NAME__, ...) \
[&](const char *__fs_func_name_) -> Result { \
if (!(__ENABLED__)) { \
R_RETURN(__EXPR__); \
} else { \
const ::ams::os::Tick __fs_start_tick = ::ams::os::GetSystemTick(); \
const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \
const ::ams::os::Tick __fs_end_tick = ::ams::os::GetSystemTick(); \
::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __PRIORITY__, __fs_start_tick, __fs_end_tick, __fs_func_name_, __HANDLE__, __VA_ARGS__); \
R_RETURN( AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME ); \
} \
}(__NAME__)
#define AMS_FS_IMPL_ACCESS_LOG_EXPLICIT_IMPL(__RESULT__, __START__, __END__, __HANDLE__, __ENABLED__, __NAME__, ...) \
[&](const char *name) -> Result { \
if (!(__ENABLED__)) { \
return __RESULT__; \
} else { \
const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__RESULT__); \
::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __START__, __END__, name, __HANDLE__, __VA_ARGS__); \
return AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME; \
} \
#define AMS_FS_IMPL_ACCESS_LOG_EXPLICIT_IMPL(__RESULT__, __START__, __END__, __HANDLE__, __ENABLED__, __NAME__, ...) \
[&](const char *__fs_func_name_) -> Result { \
if (!(__ENABLED__)) { \
R_RETURN(__RESULT__); \
} else { \
const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__RESULT__); \
::ams::fs::impl::OutputAccessLog(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __START__, __END__, __fs_func_name_, __HANDLE__, __VA_ARGS__); \
R_RETURN( AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME ); \
} \
}(__NAME__)
#define AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED_IMPL(__EXPR__, __ENABLED__, __NAME__, ...) \
[&](const char *name) -> Result { \
if (!(__ENABLED__)) { \
return (__EXPR__); \
} else { \
const ::ams::os::Tick start = ::ams::os::GetSystemTick(); \
const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \
const ::ams::os::Tick end = ::ams::os::GetSystemTick(); \
::ams::fs::impl::OutputAccessLogUnlessResultSuccess(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, start, end, name, nullptr, __VA_ARGS__); \
return AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME; \
} \
#define AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED_IMPL(__EXPR__, __ENABLED__, __NAME__, ...) \
[&](const char *__fs_func_name_) -> Result { \
if (!(__ENABLED__)) { \
R_RETURN(__EXPR__); \
} else { \
const ::ams::os::Tick __fs_start_tick = ::ams::os::GetSystemTick(); \
const auto AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME = (__EXPR__); \
const ::ams::os::Tick __fs_end_tick = ::ams::os::GetSystemTick(); \
::ams::fs::impl::OutputAccessLogUnlessResultSuccess(AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME, __fs_start_tick, __fs_end_tick, __fs_func_name_, nullptr, __VA_ARGS__); \
R_RETURN( AMS_FS_IMPL_ACCESS_LOG_RESULT_NAME ); \
} \
}(__NAME__)
/* Access log api. */
#define AMS_FS_IMPL_ACCESS_LOG(__EXPR__, __HANDLE__, ...) \
AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && ::ams::fs::impl::IsEnabledHandleAccessLog(__HANDLE__), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__)
#define AMS_FS_IMPL_ACCESS_LOG_SYSTEM(__EXPR__, __HANDLE__, ...) \
AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_System) && ::ams::fs::impl::IsEnabledHandleAccessLog(__HANDLE__), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__)
#define AMS_FS_IMPL_ACCESS_LOG_WITH_NAME(__EXPR__, __HANDLE__, __NAME__, ...) \
AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && ::ams::fs::impl::IsEnabledHandleAccessLog(__HANDLE__), __NAME__, __VA_ARGS__)
@@ -195,6 +292,37 @@ namespace ams::fs::impl {
#define AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED(__EXPR__, ...) \
AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED_IMPL((__EXPR__), ::ams::fs::impl::IsEnabledAccessLog(), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__)
/* FS Accessor logging. */
#define AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE_IMPL(__NAME__, __ENABLED__) \
do { \
if (static_cast<bool>(__ENABLED__)) { \
::ams::fs::impl::EnableFileSystemAccessorAccessLog((__NAME__)); \
} \
} while (false)
#define AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE(__NAME__) \
AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE_IMPL((__NAME__), ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_Application))
// DEBUG
#define AMS_FS_FORCE_ENABLE_SYSTEM_MOUNT_ACCESS_LOG
/* System access log api. */
#if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_FS_FORCE_ENABLE_SYSTEM_MOUNT_ACCESS_LOG)
#define AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(__EXPR__, __NAME__, ...) \
AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), nullptr, ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_System), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__)
#define AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(__NAME__) \
AMS_FS_IMPL_ACCESS_LOG_FS_ACCESSOR_ENABLE_IMPL((__NAME__), ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_System))
#else
#define AMS_FS_IMPL_ACCESS_LOG_SYSTEM_MOUNT(__EXPR__, __NAME__, ...) (__EXPR__)
#define AMS_FS_IMPL_ACCESS_LOG_SYSTEM_FS_ACCESSOR_ENABLE(__NAME__) static_cast<void>(0)
#endif
/* Specific utilities. */
#define AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM(__EXPR__, __HANDLE__, __FILESYSTEM__, ...) \
AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && (__FILESYSTEM__)->IsEnabledAccessLog(), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__)
@@ -202,5 +330,11 @@ namespace ams::fs::impl {
#define AMS_FS_IMPL_ACCESS_LOG_FILESYSTEM_WITH_NAME(__EXPR__, __HANDLE__, __FILESYSTEM__, __NAME__, ...) \
AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), __HANDLE__, ::ams::fs::impl::IsEnabledAccessLog() && (__FILESYSTEM__)->IsEnabledAccessLog(), __NAME__, __VA_ARGS__)
#define AMS_FS_IMPL_ACCESS_LOG_MOUNT(__EXPR__, __NAME__, ...) \
AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), nullptr, ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_Application), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__)
#define AMS_FS_IMPL_ACCESS_LOG_MOUNT_UNLESS_R_SUCCEEDED(__EXPR__, __NAME__, ...) \
AMS_FS_IMPL_ACCESS_LOG_UNLESS_R_SUCCEEDED_IMPL((__EXPR__), ::ams::fs::impl::IsEnabledAccessLog(::ams::fs::impl::AccessLogTarget_Application), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__)
#define AMS_FS_IMPL_ACCESS_LOG_UNMOUNT(__EXPR__, __MOUNT_NAME__, ...) \
AMS_FS_IMPL_ACCESS_LOG_IMPL((__EXPR__), nullptr, ::ams::fs::impl::IsEnabledAccessLog() && ::ams::fs::impl::IsEnabledFileSystemAccessorAccessLog(__MOUNT_NAME__), AMS_CURRENT_FUNCTION_NAME, __VA_ARGS__)

View File

@@ -19,10 +19,17 @@ namespace ams::fs::impl {
/* Delimiting of mount names. */
constexpr inline const char ReservedMountNamePrefixCharacter = '@';
constexpr inline const char * const MountNameDelimiter = ":/";
#define AMS_FS_IMPL_MOUNT_NAME_DELIMITER ":/"
#define AMS_FS_IMPL_MOUNT_NAME_DELIMITER_LEN 2
constexpr inline const char * const MountNameDelimiter = AMS_FS_IMPL_MOUNT_NAME_DELIMITER;
/* Filesystem names. */
constexpr inline const char * const HostRootFileSystemMountName = "@Host";
#define AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME "@Host"
#define AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME_LEN 5
constexpr inline const char * const HostRootFileSystemMountName = AMS_FS_IMPL_HOST_ROOT_FILE_SYSTEM_MOUNT_NAME;
constexpr inline const char * const SdCardFileSystemMountName = "@Sdcard";
constexpr inline const char * const GameCardFileSystemMountName = "@Gc";

View File

@@ -27,11 +27,13 @@ namespace ams::fs::impl {
TlsIoPriority_Background = 3,
};
#if defined(ATMOSPHERE_OS_HORIZON)
/* Ensure that TlsIo priority matches libnx priority. */
static_assert(TlsIoPriority_Normal == static_cast<TlsIoPriority>(::FsPriority_Normal));
static_assert(TlsIoPriority_Realtime == static_cast<TlsIoPriority>(::FsPriority_Realtime));
static_assert(TlsIoPriority_Low == static_cast<TlsIoPriority>(::FsPriority_Low));
static_assert(TlsIoPriority_Background == static_cast<TlsIoPriority>(::FsPriority_Background));
#endif
constexpr inline Result ConvertFsPriorityToTlsIoPriority(u8 *out, PriorityRaw priority) {
AMS_ASSERT(out != nullptr);

View File

@@ -55,7 +55,7 @@ namespace ams::fs::impl {
({ \
const ::ams::Result __tmp_fs_result = (__RESULT__); \
AMS_FS_R_CHECK_ABORT_IMPL(__tmp_fs_result, false); \
return __tmp_fs_result; \
R_THROW(__tmp_fs_result); \
})
#define AMS_FS_R_UNLESS(__EXPR__, __RESULT__) \