ams: support building unit test programs on windows/linux/macos
This commit is contained in:
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
582
libraries/libstratosphere/include/stratosphere/fs/fs_path.hpp
Normal file
582
libraries/libstratosphere/include/stratosphere/fs/fs_path.hpp
Normal 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
@@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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? */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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__)
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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__) \
|
||||
|
||||
Reference in New Issue
Block a user