Implement the NCM sysmodule (closes #91)
* Implement NCM * Modernize ncm_main * Remove unnecessary smExit * Give access to svcCallSecureMonitor * Stack size bump * Fix incorrect setup for NandUser's content storage entry * Fix a potential data abort when flushing the placeholder accessor cache * Fix HasFile and HasDirectory * Use r+b, not w+b * Misc fixes * errno begone * Fixed more stdio error handling * More main fixes * Various command improvements * Make dispatch tables great again * Fix logic inversion * Fixed content path generation * Bump heap size, fix CleanupAllPlaceHolder * Various fixes. Note: This contains debug stuff which will be removed later. I was getting tired of having to cherrypick tiny changes * Fixed placeholder/content deletion * Fixed incorrect content manager destruction * Prevent automatic placeholder creation on open * Fixed List implementation. Also lots of debug logging. * Removed debug code * Added a scope guard for WritePlaceHolder * Manually prevent placeholder/content appending * Revert "Removed debug code" This reverts commitd6ff261fcc. * Always cache placeholder file. Switch to ftell for preventing appending * Universally use EnsureEnabled * Abstract away file writing logic * Misc cleanup * Refactor placeholder cacheing * Remove debug code (again) * Revert "Remove debug code (again)" This reverts commit168447d80e. * Misc changes * Fixed file modes * Fixed ContentId/PlaceHolderId alignment * Improved type safety * Fixed reinitialization * Fixed doubleup on path creation * Remove debug code * Fixed 1.0.0 booting * Correct amount of add on content * Correct main thread stack size * lr: Introducing registered data * Reorder stratosphere Makefile * Move results to libstrat * lr: Cleanup lr_redirection * lr: lr_manager tweaks * lr: Imrpoved path handling and adjust ResolveAddOnContentPath order * lr: Organise types * Add eof newlines * lr: Eliminate unnecessary vars * lr: Unnecessary vars 2 electric boogaloo * lr: Various helpers * lr: RegisteredLocationResolver helpers * ncm: Move ncm_types to libstrat * ncm: Misc cleanup * Implement NCM * Modernize ncm_main * Remove unnecessary smExit * Give access to svcCallSecureMonitor * Stack size bump * Fix incorrect setup for NandUser's content storage entry * Fix a potential data abort when flushing the placeholder accessor cache * Fix HasFile and HasDirectory * Use r+b, not w+b * Misc fixes * errno begone * Fixed more stdio error handling * More main fixes * Various command improvements * Make dispatch tables great again * Fix logic inversion * Fixed content path generation * Bump heap size, fix CleanupAllPlaceHolder * Various fixes. Note: This contains debug stuff which will be removed later. I was getting tired of having to cherrypick tiny changes * Fixed placeholder/content deletion * Fixed incorrect content manager destruction * Prevent automatic placeholder creation on open * Fixed List implementation. Also lots of debug logging. * Removed debug code * Added a scope guard for WritePlaceHolder * Manually prevent placeholder/content appending * Revert "Removed debug code" This reverts commitd6ff261fcc. * Always cache placeholder file. Switch to ftell for preventing appending * Universally use EnsureEnabled * Abstract away file writing logic * Misc cleanup * Refactor placeholder cacheing * Remove debug code (again) * Revert "Remove debug code (again)" This reverts commit168447d80e. * Misc changes * Fixed file modes * Fixed ContentId/PlaceHolderId alignment * Improved type safety * Fixed reinitialization * Fixed doubleup on path creation * Remove debug code * Fixed 1.0.0 booting * Correct amount of add on content * Correct main thread stack size * lr: Introducing registered data * Reorder stratosphere Makefile * Move results to libstrat * lr: Cleanup lr_redirection * lr: lr_manager tweaks * lr: Imrpoved path handling and adjust ResolveAddOnContentPath order * lr: Organise types * Add eof newlines * lr: Eliminate unnecessary vars * lr: Unnecessary vars 2 electric boogaloo * lr: Various helpers * lr: RegisteredLocationResolver helpers * ncm: Move ncm_types to libstrat * ncm: Misc cleanup * Updated AddOnContentLocationResolver and RegisteredLocationResolver to 9.0.0 * Finished updating lr to 9.0.0 * Updated NCM to 9.0.0 * Fix libstrat includes * Fixed application launching * title_id_2 -> owner_tid * Updated to new-ipc * Change to using pure virtuals * Title Id -> Program Id * Fixed compilation against master * std::scoped_lock<> -> std::scoped_lock * Adopted R_UNLESS and R_CONVERT * Prefix namespace to Results * Adopt std::numeric_limits * Fixed incorrect error handling in ReadFile * Adopted AMS_ABORT_UNLESS * Adopt util::GenerateUuid() * Syntax improvements * ncm_types: Address review * Address more review comments * Updated copyrights * Address more feedback * More feedback addressed * More changes * Move dispatch tables out of interface files * Addressed remaining comments * lr: move into libstratosphere * ncm: Fix logic inversion * lr: Add comments * lr: Remove whitespace * ncm: Start addressing feedback * ncm: Cleanup InitializeContentManager * lr: support client-side usage * lr_service -> lr_api * ncm: Begin refactoring content manager * ncm: More content manager improvements * ncm: Content manager mount improvements * ldr: use lr bindings * lr bindings usage: minor fixes * ncm/lr: Pointer placement * ncm: placeholder accessor cleanup * ncm: minor fixes * ncm: refactor rights cache * ncm: content meta database cleanup * ncm: move content meta database impl out of interface file * ncm: Use const ContentMetaKey & * ncm: fix other non-const ContentMetaKey references * ncm: content meta database cleanup * ncm: content storage fixes for 2.0.0 * ncm: add missing end of file newlines * ncm: implement ContentMetaReader * ncm: client-side api * ncm: trim trailing spaces * ncm: FS_MAX_PATH-1 -> fs::EntryNameLengthMax * ncm: Use PathString and Path * fs: implement accessor wrappers for ncm * fs: implement user fs wrappers * fs: add MountSdCard * ncm: move to content manager impl * ncm: fix up main * kvdb: use fs:: * fs: Add wrappers needed for ncm * ncm: use fs bindings, other refactoring * ncm: minor fixes * fsa: fix ReadFile without size output * fs: add substorage, rom path tool * ncm: fix dangling fsdev usage * fs: fix bug in Commit * fs: fixed incorrect mode check * fs: implement Mount(System)Data * ncm: don't delete hos * results: add R_SUCCEED_IF * ams-except-ncm: use R_SUCCEED_IF * ncm: added comments * ncm: fix api definitions * ncm: use R_SUCCEED_IF * pm: think of the savings * ncm: employ kernel strats * ncm: Nintendo has 5 MiB of heap. Give ourselves 4 to be safe, pending analysis * ncm: refactor IDs, split types header into many headers * ams.mitm: use fs bindings instead of stdio * fs: SystemData uses SystemDataId * ncm: improve meta-db accuracy * ncm: inline getlatestkey * fs: improve UnsupportedOperation results * fs: modernize mount utils * ams: misc fixes for merge-errors * fs: improve unsupportedoperation results * git subrepo pull emummc subrepo: subdir: "emummc" merged: "d12dd546" upstream: origin: "https://github.com/m4xw/emuMMC" branch: "develop" commit: "d12dd546" git-subrepo: version: "0.4.1" origin: "???" commit: "???" * util: add boundedmap * ncm: minor style fixes * ncm: don't unmount if mounting fails * lr: bug fixes * ncm: implement ncm.for-initialize + ncm.for-safemode * lr: ncm::ProgramId::Invalid -> ncm::InvalidProgramId * ncm: fix open directory mode on 1.0.0 * ncm: fix fs use, implement more of < 4.0.0 for-initialize/safemode * ncm: implement packagedcontent -> content for building metadb * ncm: fix save data flag management * ncm: address some review suggestions (thanks @leoetlino!) * updater: use fs bindings * fs: implement MountCode * fs: prefer make_unique to operator new * ncm: implement remaining ContentMetaDatabaseBuilder functionality Co-authored-by: Michael Scire <SciresM@gmail.com>
This commit is contained in:
58
libraries/libstratosphere/include/stratosphere/fs/fs_bis.hpp
Normal file
58
libraries/libstratosphere/include/stratosphere/fs/fs_bis.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere/fs/fs_common.hpp>
|
||||
#include <stratosphere/fs/fs_istorage.hpp>
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
enum class BisPartitionId {
|
||||
/* Boot0 */
|
||||
BootPartition1Root = 0,
|
||||
|
||||
/* Boot1 */
|
||||
BootPartition2Root = 10,
|
||||
|
||||
/* Non-Boot */
|
||||
UserDataRoot = 20,
|
||||
BootConfigAndPackage2Part1 = 21,
|
||||
BootConfigAndPackage2Part2 = 22,
|
||||
BootConfigAndPackage2Part3 = 23,
|
||||
BootConfigAndPackage2Part4 = 24,
|
||||
BootConfigAndPackage2Part5 = 25,
|
||||
BootConfigAndPackage2Part6 = 26,
|
||||
CalibrationBinary = 27,
|
||||
CalibrationFile = 28,
|
||||
SafeMode = 29,
|
||||
User = 30,
|
||||
System = 31,
|
||||
SystemProperEncryption = 32,
|
||||
SystemProperPartition = 33,
|
||||
SignedSystemPartitionOnSafeMode = 34,
|
||||
};
|
||||
|
||||
const char *GetBisMountName(BisPartitionId id);
|
||||
|
||||
Result MountBis(BisPartitionId id, const char *root_path);
|
||||
Result MountBis(const char *name, BisPartitionId id);
|
||||
|
||||
void SetBisRootForHost(BisPartitionId id, const char *root_path);
|
||||
|
||||
Result OpenBisPartition(std::unique_ptr<fs::IStorage> *out, BisPartitionId id);
|
||||
|
||||
Result InvalidateBisCache();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
#include <stratosphere/ncm/ncm_ids.hpp>
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
Result MountCode(const char *name, const char *path, ncm::ProgramId program_id);
|
||||
|
||||
}
|
||||
@@ -15,13 +15,34 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include "../os.hpp"
|
||||
#include "../ncm.hpp"
|
||||
#include "../sf.hpp"
|
||||
#include <stratosphere/os.hpp>
|
||||
#include <stratosphere/ncm/ncm_ids.hpp>
|
||||
#include <stratosphere/sf.hpp>
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
/* TODO: Better place for this? */
|
||||
constexpr inline size_t MountNameLengthMax = 15;
|
||||
struct Int64 {
|
||||
u32 low;
|
||||
u32 high;
|
||||
|
||||
}
|
||||
constexpr ALWAYS_INLINE void Set(s64 v) {
|
||||
this->low = static_cast<u32>((v & static_cast<u64>(0x00000000FFFFFFFFul)) >> 0);
|
||||
this->high = static_cast<u32>((v & static_cast<u64>(0xFFFFFFFF00000000ul)) >> 32);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE s64 Get() const {
|
||||
return (static_cast<s64>(this->high) << 32) | (static_cast<s64>(this->low));
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE Int64 &operator=(s64 v) {
|
||||
this->Set(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE operator s64() const {
|
||||
return this->Get();
|
||||
}
|
||||
};
|
||||
static_assert(std::is_pod<Int64>::value);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
#include <stratosphere/ncm/ncm_ids.hpp>
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
enum ContentType {
|
||||
ContentType_Meta = 0,
|
||||
ContentType_Control = 1,
|
||||
ContentType_Manual = 2,
|
||||
ContentType_Logo = 3,
|
||||
ContentType_Data = 4,
|
||||
};
|
||||
|
||||
Result MountContent(const char *name, const char *path, ContentType content_type);
|
||||
Result MountContent(const char *name, const char *path, ncm::ProgramId id, ContentType content_type);
|
||||
Result MountContent(const char *name, const char *path, ncm::DataId id, ContentType content_type);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
enum class ContentStorageId : u32 {
|
||||
System = 0,
|
||||
User = 1,
|
||||
SdCard = 2,
|
||||
};
|
||||
|
||||
constexpr inline const char * const ContentStorageDirectoryName = "Contents";
|
||||
|
||||
const char *GetContentStorageMountName(ContentStorageId id);
|
||||
|
||||
Result MountContentStorage(ContentStorageId id);
|
||||
Result MountContentStorage(const char *name, ContentStorageId id);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_dbm_rom_types.hpp"
|
||||
#include "fs_dbm_rom_path_tool.hpp"
|
||||
#include "fs_dbm_rom_key_value_storage.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
class HierarchicalRomFileTable {
|
||||
public:
|
||||
using Position = u32;
|
||||
|
||||
struct FindPosition {
|
||||
Position next_dir;
|
||||
Position next_file;
|
||||
};
|
||||
static_assert(std::is_pod<FindPosition>::value);
|
||||
|
||||
using DirectoryInfo = RomDirectoryInfo;
|
||||
using FileInfo = RomFileInfo;
|
||||
|
||||
static constexpr RomFileId ConvertToFileId(Position pos) {
|
||||
return static_cast<RomFileId>(pos);
|
||||
}
|
||||
private:
|
||||
static constexpr inline Position InvalidPosition = ~Position();
|
||||
static constexpr inline Position RootPosition = 0;
|
||||
static constexpr inline size_t ReservedDirectoryCount = 1;
|
||||
|
||||
static constexpr RomDirectoryId ConvertToDirectoryId(Position pos) {
|
||||
return static_cast<RomDirectoryId>(pos);
|
||||
}
|
||||
|
||||
static constexpr Position ConvertToPosition(RomDirectoryId id) {
|
||||
return static_cast<Position>(id);
|
||||
}
|
||||
|
||||
static_assert(std::is_same<RomDirectoryId, RomFileId>::value);
|
||||
|
||||
struct RomDirectoryEntry {
|
||||
Position next;
|
||||
Position dir;
|
||||
Position file;
|
||||
};
|
||||
static_assert(std::is_pod<RomDirectoryEntry>::value);
|
||||
|
||||
struct RomFileEntry {
|
||||
Position next;
|
||||
FileInfo info;
|
||||
};
|
||||
static_assert(std::is_pod<RomFileEntry>::value);
|
||||
|
||||
static constexpr inline u32 MaxKeyLength = RomPathTool::MaxPathLength;
|
||||
|
||||
template<typename ImplKeyType, typename ClientKeyType, typename ValueType>
|
||||
class EntryMapTable : public RomKeyValueStorage<ImplKeyType, ValueType, MaxKeyLength> {
|
||||
public:
|
||||
using ImplKey = ImplKeyType;
|
||||
using ClientKey = ClientKeyType;
|
||||
using Value = ValueType;
|
||||
using Position = HierarchicalRomFileTable::Position;
|
||||
using Base = RomKeyValueStorage<ImplKeyType, ValueType, MaxKeyLength>;
|
||||
public:
|
||||
Result Add(Position *out, const ClientKeyType &key, const Value &value) {
|
||||
return Base::AddImpl(out, key.key, key.Hash(), key.name.path, key.name.length * sizeof(RomPathChar), value);
|
||||
}
|
||||
|
||||
Result Get(Position *out_pos, Value *out_val, const ClientKeyType &key) {
|
||||
return Base::GetImpl(out_pos, out_val, key.key, key.Hash(), key.name.path, key.name.length * sizeof(RomPathChar));
|
||||
}
|
||||
|
||||
Result GetByPosition(ImplKey *out_key, Value *out_val, Position pos) {
|
||||
return Base::GetByPosition(out_key, out_val, pos);
|
||||
}
|
||||
|
||||
Result GetByPosition(ImplKey *out_key, Value *out_val, void *out_aux, size_t *out_aux_size, Position pos) {
|
||||
return Base::GetByPosition(out_key, out_val, out_aux, out_aux_size, pos);
|
||||
}
|
||||
|
||||
Result SetByPosition(Position pos, const Value &value) {
|
||||
return Base::SetByPosition(pos, value);
|
||||
}
|
||||
};
|
||||
|
||||
struct RomEntryKey {
|
||||
Position parent;
|
||||
|
||||
bool IsEqual(const RomEntryKey &rhs, const void *aux_lhs, size_t aux_lhs_size, const void *aux_rhs, size_t aux_rhs_size) const {
|
||||
if (this->parent != rhs.parent) {
|
||||
return false;
|
||||
}
|
||||
if (aux_lhs_size != aux_rhs_size) {
|
||||
return false;
|
||||
}
|
||||
return RomPathTool::IsEqualPath(reinterpret_cast<const RomPathChar *>(aux_lhs), reinterpret_cast<const RomPathChar *>(aux_rhs), aux_lhs_size / sizeof(RomPathChar));
|
||||
}
|
||||
};
|
||||
static_assert(std::is_pod<RomEntryKey>::value);
|
||||
|
||||
struct EntryKey {
|
||||
RomEntryKey key;
|
||||
RomPathTool::RomEntryName name;
|
||||
|
||||
constexpr u32 Hash() const {
|
||||
u32 hash = this->key.parent ^ 123456789;
|
||||
const RomPathChar *name = this->name.path;
|
||||
const RomPathChar *end = name + this->name.length;
|
||||
while (name < end) {
|
||||
const u32 cur = static_cast<u32>(static_cast<std::make_unsigned<RomPathChar>::type>(*(name++)));
|
||||
hash = ((hash >> 5) | (hash << 27)) ^ cur;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
static_assert(std::is_pod<EntryKey>::value);
|
||||
|
||||
using DirectoryEntryMapTable = EntryMapTable<RomEntryKey, EntryKey, RomDirectoryEntry>;
|
||||
using FileEntryMapTable = EntryMapTable<RomEntryKey, EntryKey, RomFileEntry>;
|
||||
private:
|
||||
DirectoryEntryMapTable dir_table;
|
||||
FileEntryMapTable file_table;
|
||||
public:
|
||||
static s64 QueryDirectoryEntryStorageSize(u32 count);
|
||||
static s64 QueryDirectoryEntryBucketStorageSize(s64 count);
|
||||
static s64 QueryFileEntryStorageSize(u32 count);
|
||||
static s64 QueryFileEntryBucketStorageSize(s64 count);
|
||||
|
||||
static Result Format(SubStorage dir_bucket, SubStorage file_bucket);
|
||||
public:
|
||||
HierarchicalRomFileTable();
|
||||
|
||||
constexpr u32 GetDirectoryEntryCount() const {
|
||||
return this->dir_table.GetEntryCount();
|
||||
}
|
||||
|
||||
constexpr u32 GetFileEntryCount() const {
|
||||
return this->file_table.GetEntryCount();
|
||||
}
|
||||
|
||||
Result Initialize(SubStorage dir_bucket, SubStorage dir_entry, SubStorage file_bucket, SubStorage file_entry);
|
||||
void Finalize();
|
||||
|
||||
Result CreateRootDirectory();
|
||||
Result CreateDirectory(RomDirectoryId *out, const RomPathChar *path, const DirectoryInfo &info);
|
||||
Result CreateFile(RomFileId *out, const RomPathChar *path, const FileInfo &info);
|
||||
Result ConvertPathToDirectoryId(RomDirectoryId *out, const RomPathChar *path);
|
||||
Result ConvertPathToFileId(RomFileId *out, const RomPathChar *path);
|
||||
|
||||
Result GetDirectoryInformation(DirectoryInfo *out, const RomPathChar *path);
|
||||
Result GetDirectoryInformation(DirectoryInfo *out, RomDirectoryId id);
|
||||
|
||||
Result OpenFile(FileInfo *out, const RomPathChar *path);
|
||||
Result OpenFile(FileInfo *out, RomFileId id);
|
||||
|
||||
Result FindOpen(FindPosition *out, const RomPathChar *path);
|
||||
Result FindOpen(FindPosition *out, RomDirectoryId id);
|
||||
|
||||
Result FindNextDirectory(RomPathChar *out, FindPosition *find, size_t length);
|
||||
Result FindNextFile(RomPathChar *out, FindPosition *find, size_t length);
|
||||
|
||||
Result QueryRomFileSystemSize(s64 *out_dir_entry_size, s64 *out_file_entry_size);
|
||||
private:
|
||||
Result GetGrandParent(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, Position pos, RomPathTool::RomEntryName name, const RomPathChar *path);
|
||||
|
||||
Result FindParentDirectoryRecursive(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, RomPathTool::PathParser *parser, const RomPathChar *path);
|
||||
|
||||
Result FindPathRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, bool is_dir, const RomPathChar *path);
|
||||
Result FindDirectoryRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, const RomPathChar *path);
|
||||
Result FindFileRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, const RomPathChar *path);
|
||||
|
||||
Result CheckSameEntryExists(const EntryKey &key, Result if_exists);
|
||||
|
||||
Result GetDirectoryEntry(Position *out_pos, RomDirectoryEntry *out_entry, const EntryKey &key);
|
||||
Result GetDirectoryEntry(RomDirectoryEntry *out_entry, RomDirectoryId id);
|
||||
|
||||
Result GetFileEntry(Position *out_pos, RomFileEntry *out_entry, const EntryKey &key);
|
||||
Result GetFileEntry(RomFileEntry *out_entry, RomFileId id);
|
||||
|
||||
Result GetDirectoryInformation(DirectoryInfo *out, const EntryKey &key);
|
||||
|
||||
Result OpenFile(FileInfo *out, const EntryKey &key);
|
||||
|
||||
Result FindOpen(FindPosition *out, const EntryKey &key);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_dbm_rom_types.hpp"
|
||||
#include "fs_substorage.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
template<typename KeyType, typename ValueType, size_t MaxAuxiliarySize>
|
||||
class RomKeyValueStorage {
|
||||
public:
|
||||
using Key = KeyType;
|
||||
using Value = ValueType;
|
||||
using Position = u32;
|
||||
using BucketIndex = s64;
|
||||
|
||||
struct FindIndex {
|
||||
BucketIndex ind;
|
||||
Position pos;
|
||||
};
|
||||
static_assert(std::is_pod<FindIndex>::value);
|
||||
private:
|
||||
static constexpr inline Position InvalidPosition = ~Position();
|
||||
|
||||
struct Element {
|
||||
Key key;
|
||||
Value value;
|
||||
Position next;
|
||||
u32 size;
|
||||
};
|
||||
static_assert(std::is_pod<Element>::value);
|
||||
private:
|
||||
s64 bucket_count;
|
||||
SubStorage bucket_storage;
|
||||
SubStorage kv_storage;
|
||||
s64 total_entry_size;
|
||||
u32 entry_count;
|
||||
public:
|
||||
static constexpr s64 QueryBucketStorageSize(s64 num) {
|
||||
return num * sizeof(Position);
|
||||
}
|
||||
|
||||
static constexpr s64 QueryBucketCount(s64 size) {
|
||||
return size / sizeof(Position);
|
||||
}
|
||||
|
||||
static constexpr s64 QueryKeyValueStorageSize(u32 num) {
|
||||
return num * sizeof(Element);
|
||||
}
|
||||
|
||||
static Result Format(SubStorage bucket, s64 count) {
|
||||
const Position pos = InvalidPosition;
|
||||
for (s64 i = 0; i < count; i++) {
|
||||
R_TRY(bucket.Write(i * sizeof(pos), std::addressof(pos), sizeof(pos)));
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
public:
|
||||
RomKeyValueStorage() : bucket_count(), bucket_storage(), kv_storage(), total_entry_size(), entry_count() { /* ... */ }
|
||||
|
||||
Result Initialize(const SubStorage &bucket, s64 count, const SubStorage &kv) {
|
||||
AMS_ASSERT(count > 0);
|
||||
this->bucket_storage = bucket;
|
||||
this->kv_storage = kv;
|
||||
this->bucket_count = count;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void Finalize() {
|
||||
this->bucket_storage = SubStorage();
|
||||
this->kv_storage = SubStorage();
|
||||
this->bucket_count = 0;
|
||||
}
|
||||
|
||||
s64 GetTotalEntrySize() const {
|
||||
return this->total_entry_size;
|
||||
}
|
||||
|
||||
Result GetFreeSize(s64 *out) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
s64 kv_size = 0;
|
||||
R_TRY(this->kv_storage.GetSize(std::addressof(kv_size)));
|
||||
*out = kv_size - this->total_entry_size;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
constexpr u32 GetEntryCount() const {
|
||||
return this->entry_count;
|
||||
}
|
||||
|
||||
Result Add(const Key &key, u32 hash_key, const void *aux, size_t aux_size, const Value &value) {
|
||||
AMS_ASSERT(aux != nullptr);
|
||||
AMS_ASSERT(aux_size <= MaxAuxiliarySize);
|
||||
Position pos;
|
||||
return this->AddImpl(std::addressof(pos), key, hash_key, aux, aux_size, value);
|
||||
}
|
||||
|
||||
Result Get(Value *out, const Key &key, u32 hash_key, const void *aux, size_t aux_size) {
|
||||
AMS_ASSERT(aux != nullptr);
|
||||
AMS_ASSERT(aux_size <= MaxAuxiliarySize);
|
||||
Position pos;
|
||||
return this->GetImpl(std::addressof(pos), out, key, hash_key, aux, aux_size);
|
||||
}
|
||||
|
||||
Result FindOpen(FindIndex *out) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
out->ind = static_cast<BucketIndex>(-1);
|
||||
out->pos = InvalidPosition;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result FindNext(Key *out_key, Value *out_val, FindIndex *find) {
|
||||
AMS_ASSERT(out_key != nullptr);
|
||||
AMS_ASSERT(out_val != nullptr);
|
||||
AMS_ASSERT(find != nullptr);
|
||||
|
||||
BucketIndex ind = find->ind;
|
||||
R_UNLESS((ind < this->bucket_count) || ind == static_cast<BucketIndex>(-1), fs::ResultDbmFindKeyFinished());
|
||||
|
||||
s64 kv_size;
|
||||
R_TRY(this->kv_storage.GetSize(std::addressof(kv_size)));
|
||||
|
||||
while (true) {
|
||||
if (find->pos != InvalidPosition) {
|
||||
Element elem;
|
||||
R_TRY(this->ReadKeyValue(std::addressof(elem), find->pos));
|
||||
|
||||
AMS_ASSERT(elem.next == InvalidPosition || elem.next < kv_size);
|
||||
find->pos = elem.next;
|
||||
*out_key = elem.key;
|
||||
*out_val = elem.val;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
ind++;
|
||||
if (ind == this->bucket_count) {
|
||||
find->ind = ind;
|
||||
find->pos = InvalidPosition;
|
||||
return fs::ResultDbmFindKeyFinished();
|
||||
}
|
||||
|
||||
Position pos;
|
||||
R_TRY(this->ReadBucket(std::addressof(pos), ind));
|
||||
AMS_ASSERT(pos == InvalidPosition || pos < kv_size);
|
||||
|
||||
if (pos != InvalidPosition) {
|
||||
find->ind = ind;
|
||||
find->pos = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
protected:
|
||||
Result AddImpl(Position *out, const Key &key, u32 hash_key, const void *aux, size_t aux_size, const Value &value) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(aux != nullptr);
|
||||
AMS_ASSERT(this->bucket_count > 0);
|
||||
|
||||
{
|
||||
Position pos, prev_pos;
|
||||
Element elem;
|
||||
|
||||
const Result find_res = this->FindImpl(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size);
|
||||
R_UNLESS(R_FAILED(find_res), fs::ResultDbmAlreadyExists());
|
||||
R_UNLESS(fs::ResultDbmKeyNotFound::Includes(find_res), find_res);
|
||||
}
|
||||
|
||||
Position pos;
|
||||
R_TRY(this->AllocateEntry(std::addressof(pos), aux_size));
|
||||
|
||||
Position next_pos;
|
||||
R_TRY(this->LinkEntry(std::addressof(next_pos), pos, hash_key));
|
||||
|
||||
const Element elem = { key, value, next_pos, static_cast<u32>(aux_size) };
|
||||
R_TRY(this->WriteKeyValue(std::addressof(elem), pos, aux, aux_size));
|
||||
|
||||
*out = pos;
|
||||
this->entry_count++;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetImpl(Position *out_pos, Value *out_val, const Key &key, u32 hash_key, const void *aux, size_t aux_size) {
|
||||
AMS_ASSERT(out_pos != nullptr);
|
||||
AMS_ASSERT(out_val != nullptr);
|
||||
AMS_ASSERT(aux != nullptr);
|
||||
|
||||
Position pos, prev_pos;
|
||||
Element elem;
|
||||
R_TRY(this->FindImpl(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size));
|
||||
|
||||
*out_pos = pos;
|
||||
*out_val = elem.value;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetByPosition(Key *out_key, Value *out_val, Position pos) {
|
||||
AMS_ASSERT(out_key != nullptr);
|
||||
AMS_ASSERT(out_val != nullptr);
|
||||
|
||||
Element elem;
|
||||
R_TRY(this->ReadKeyValue(std::addressof(elem), pos));
|
||||
|
||||
*out_key = elem.key;
|
||||
*out_val = elem.value;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetByPosition(Key *out_key, Value *out_val, void *out_aux, size_t *out_aux_size, Position pos) {
|
||||
AMS_ASSERT(out_key != nullptr);
|
||||
AMS_ASSERT(out_val != nullptr);
|
||||
AMS_ASSERT(out_aux != nullptr);
|
||||
AMS_ASSERT(out_aux_size != nullptr);
|
||||
|
||||
Element elem;
|
||||
R_TRY(this->ReadKeyValue(std::addressof(elem), out_aux, out_aux_size, pos));
|
||||
|
||||
*out_key = elem.key;
|
||||
*out_val = elem.value;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result SetByPosition(Position pos, const Value &value) {
|
||||
Element elem;
|
||||
R_TRY(this->ReadKeyValue(std::addressof(elem), pos));
|
||||
elem.value = value;
|
||||
return this->WriteKeyValue(std::addressof(elem), pos, nullptr, 0);
|
||||
}
|
||||
private:
|
||||
BucketIndex HashToBucket(u32 hash_key) const {
|
||||
return hash_key % this->bucket_count;
|
||||
}
|
||||
|
||||
Result FindImpl(Position *out_pos, Position *out_prev, Element *out_elem, const Key &key, u32 hash_key, const void *aux, size_t aux_size) {
|
||||
AMS_ASSERT(out_pos != nullptr);
|
||||
AMS_ASSERT(out_prev != nullptr);
|
||||
AMS_ASSERT(out_elem != nullptr);
|
||||
AMS_ASSERT(aux != nullptr);
|
||||
AMS_ASSERT(this->bucket_count > 0);
|
||||
|
||||
*out_pos = 0;
|
||||
*out_prev = 0;
|
||||
|
||||
const BucketIndex ind = HashToBucket(hash_key);
|
||||
|
||||
Position cur;
|
||||
R_TRY(this->ReadBucket(std::addressof(cur), ind));
|
||||
|
||||
s64 kv_size;
|
||||
R_TRY(this->kv_storage.GetSize(std::addressof(kv_size)));
|
||||
AMS_ASSERT(cur == InvalidPosition || cur < kv_size);
|
||||
|
||||
R_UNLESS(cur != InvalidPosition, fs::ResultDbmKeyNotFound());
|
||||
|
||||
u8 *buf = static_cast<u8 *>(::ams::fs::impl::Allocate(MaxAuxiliarySize));
|
||||
R_UNLESS(buf != nullptr, fs::ResultAllocationFailureInDbmRomKeyValueStorage());
|
||||
ON_SCOPE_EXIT { ::ams::fs::impl::Deallocate(buf, MaxAuxiliarySize); };
|
||||
|
||||
while (true) {
|
||||
size_t cur_aux_size;
|
||||
R_TRY(this->ReadKeyValue(out_elem, buf, std::addressof(cur_aux_size), cur));
|
||||
|
||||
if (key.IsEqual(out_elem->key, aux, aux_size, buf, cur_aux_size)) {
|
||||
*out_pos = cur;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
*out_prev = cur;
|
||||
cur = out_elem->next;
|
||||
R_UNLESS(cur != InvalidPosition, fs::ResultDbmKeyNotFound());
|
||||
}
|
||||
}
|
||||
|
||||
Result AllocateEntry(Position *out, size_t aux_size) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
s64 kv_size;
|
||||
R_TRY(this->kv_storage.GetSize(std::addressof(kv_size)));
|
||||
const size_t end_pos = this->total_entry_size + sizeof(Element) + aux_size;
|
||||
R_UNLESS(end_pos <= static_cast<size_t>(kv_size), fs::ResultDbmKeyFull());
|
||||
|
||||
*out = static_cast<Position>(this->total_entry_size);
|
||||
|
||||
this->total_entry_size = util::AlignUp(static_cast<s64>(end_pos), s64(4));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result LinkEntry(Position *out, Position pos, u32 hash_key) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
const BucketIndex ind = HashToBucket(hash_key);
|
||||
|
||||
Position next;
|
||||
R_TRY(this->ReadBucket(std::addressof(next), ind));
|
||||
|
||||
s64 kv_size;
|
||||
R_TRY(this->kv_storage.GetSize(std::addressof(kv_size)));
|
||||
AMS_ASSERT(next == InvalidPosition || next < kv_size);
|
||||
|
||||
R_TRY(this->WriteBucket(pos, ind));
|
||||
|
||||
*out = next;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ReadBucket(Position *out, BucketIndex ind) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(ind < this->bucket_count);
|
||||
|
||||
const s64 offset = ind * sizeof(Position);
|
||||
return this->bucket_storage.Read(offset, out, sizeof(*out));
|
||||
}
|
||||
|
||||
Result WriteBucket(Position pos, BucketIndex ind) {
|
||||
AMS_ASSERT(ind < this->bucket_count);
|
||||
|
||||
const s64 offset = ind * sizeof(Position);
|
||||
return this->bucket_storage.Write(offset, std::addressof(pos), sizeof(pos));
|
||||
}
|
||||
|
||||
Result ReadKeyValue(Element *out, Position pos) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
s64 kv_size;
|
||||
R_TRY(this->kv_storage.GetSize(std::addressof(kv_size)));
|
||||
AMS_ASSERT(pos < kv_size);
|
||||
|
||||
return this->kv_storage.Read(pos, out, sizeof(*out));
|
||||
}
|
||||
|
||||
Result ReadKeyValue(Element *out, void *out_aux, size_t *out_aux_size, Position pos) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(out_aux != nullptr);
|
||||
AMS_ASSERT(out_aux_size != nullptr);
|
||||
|
||||
R_TRY(this->ReadKeyValue(out, pos));
|
||||
|
||||
*out_aux_size = out->size;
|
||||
if (out->size > 0) {
|
||||
R_TRY(this->kv_storage.Read(pos + sizeof(*out), out_aux, out->size));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result WriteKeyValue(const Element *elem, Position pos, const void *aux, size_t aux_size) {
|
||||
AMS_ASSERT(elem != nullptr);
|
||||
AMS_ASSERT(aux != nullptr);
|
||||
|
||||
s64 kv_size;
|
||||
R_TRY(this->kv_storage.GetSize(std::addressof(kv_size)));
|
||||
AMS_ASSERT(pos < kv_size);
|
||||
|
||||
R_TRY(this->kv_storage.Write(pos, elem, sizeof(*elem)));
|
||||
|
||||
if (aux != nullptr && aux_size > 0) {
|
||||
R_TRY(this->kv_storage.Write(pos + sizeof(*elem), aux, aux_size));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_dbm_rom_types.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
namespace RomPathTool {
|
||||
|
||||
constexpr inline u32 MaxPathLength = 0x300;
|
||||
|
||||
struct RomEntryName {
|
||||
size_t length;
|
||||
const RomPathChar *path;
|
||||
};
|
||||
static_assert(std::is_pod<RomEntryName>::value);
|
||||
|
||||
constexpr void InitializeRomEntryName(RomEntryName *entry) {
|
||||
AMS_ABORT_UNLESS(entry != nullptr);
|
||||
entry->length = 0;
|
||||
}
|
||||
|
||||
constexpr inline bool IsSeparator(RomPathChar c) {
|
||||
return c == RomStringTraits::DirectorySeparator;
|
||||
}
|
||||
|
||||
constexpr inline bool IsNullTerminator(RomPathChar c) {
|
||||
return c == RomStringTraits::NullTerminator;
|
||||
}
|
||||
|
||||
constexpr inline bool IsDot(RomPathChar c) {
|
||||
return c == RomStringTraits::Dot;
|
||||
}
|
||||
|
||||
constexpr inline bool IsCurrentDirectory(const RomEntryName &name) {
|
||||
return name.length == 1 && IsDot(name.path[0]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsCurrentDirectory(const RomPathChar *p, size_t length) {
|
||||
AMS_ABORT_UNLESS(p != nullptr);
|
||||
return length == 1 && IsDot(p[0]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsCurrentDirectory(const RomPathChar *p) {
|
||||
AMS_ABORT_UNLESS(p != nullptr);
|
||||
return IsDot(p[0]) && IsNullTerminator(p[1]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsParentDirectory(const RomEntryName &name) {
|
||||
return name.length == 2 && IsDot(name.path[0]) && IsDot(name.path[1]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsParentDirectory(const RomPathChar *p) {
|
||||
AMS_ABORT_UNLESS(p != nullptr);
|
||||
return IsDot(p[0]) && IsDot(p[1]) && IsNullTerminator(p[2]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsParentDirectory(const RomPathChar *p, size_t length) {
|
||||
AMS_ABORT_UNLESS(p != nullptr);
|
||||
return length == 2 && IsDot(p[0]) && IsDot(p[1]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsEqualPath(const RomPathChar *lhs, const RomPathChar *rhs, size_t length) {
|
||||
AMS_ABORT_UNLESS(lhs != nullptr);
|
||||
AMS_ABORT_UNLESS(rhs != nullptr);
|
||||
return std::strncmp(lhs, rhs, length) == 0;
|
||||
}
|
||||
|
||||
constexpr inline bool IsEqualName(const RomEntryName &lhs, const RomPathChar *rhs) {
|
||||
AMS_ABORT_UNLESS(rhs != nullptr);
|
||||
if (strnlen(rhs, MaxPathLength) != lhs.length) {
|
||||
return false;
|
||||
}
|
||||
return IsEqualPath(lhs.path, rhs, lhs.length);
|
||||
}
|
||||
|
||||
constexpr inline bool IsEqualName(const RomEntryName &lhs, const RomEntryName &rhs) {
|
||||
if (lhs.length != rhs.length) {
|
||||
return false;
|
||||
}
|
||||
return IsEqualPath(lhs.path, rhs.path, lhs.length);
|
||||
}
|
||||
|
||||
Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p);
|
||||
|
||||
class PathParser {
|
||||
private:
|
||||
const RomPathChar *prev_path_start;
|
||||
const RomPathChar *prev_path_end;
|
||||
const RomPathChar *next_path;
|
||||
bool finished;
|
||||
public:
|
||||
constexpr PathParser() : prev_path_start(), prev_path_end(), next_path(), finished() { /* ... */ }
|
||||
|
||||
Result Initialize(const RomPathChar *path);
|
||||
void Finalize();
|
||||
|
||||
bool IsFinished() const;
|
||||
bool IsDirectoryPath() const;
|
||||
|
||||
Result GetAsDirectoryName(RomEntryName *out) const;
|
||||
Result GetAsFileName(RomEntryName *out) const;
|
||||
|
||||
Result GetNextDirectoryName(RomEntryName *out);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
using RomPathChar = char;
|
||||
using RomFileId = s32;
|
||||
using RomDirectoryId = s32;
|
||||
|
||||
struct RomFileSystemInformation {
|
||||
s64 size;
|
||||
s64 directory_bucket_offset;
|
||||
s64 directory_bucket_size;
|
||||
s64 directory_entry_offset;
|
||||
s64 directory_entry_size;
|
||||
s64 file_bucket_offset;
|
||||
s64 file_bucket_size;
|
||||
s64 file_entry_offset;
|
||||
s64 file_entry_size;
|
||||
s64 body_offset;
|
||||
};
|
||||
static_assert(std::is_pod<RomFileSystemInformation>::value);
|
||||
static_assert(sizeof(RomFileSystemInformation) == 0x50);
|
||||
|
||||
struct RomDirectoryInfo {
|
||||
/* ... */
|
||||
};
|
||||
static_assert(std::is_pod<RomDirectoryInfo>::value);
|
||||
|
||||
struct RomFileInfo {
|
||||
Int64 offset;
|
||||
Int64 size;
|
||||
};
|
||||
static_assert(std::is_pod<RomFileInfo>::value);
|
||||
|
||||
namespace RomStringTraits {
|
||||
|
||||
constexpr inline char DirectorySeparator = '/';
|
||||
constexpr inline char NullTerminator = '\x00';
|
||||
constexpr inline char Dot = '.';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,4 +22,12 @@ namespace ams::fs {
|
||||
|
||||
using DirectoryEntry = ::FsDirectoryEntry;
|
||||
|
||||
struct DirectoryHandle {
|
||||
void *handle;
|
||||
};
|
||||
|
||||
Result ReadDirectory(s64 *out_count, DirectoryEntry *out_entries, DirectoryHandle handle, s64 max_entries);
|
||||
Result GetDirectoryEntryCount(s64 *out, DirectoryHandle handle);
|
||||
void CloseDirectory(DirectoryHandle handle);
|
||||
|
||||
}
|
||||
|
||||
@@ -60,4 +60,19 @@ namespace ams::fs {
|
||||
|
||||
static_assert(std::is_pod<WriteOption>::value && sizeof(WriteOption) == sizeof(u32));
|
||||
|
||||
struct FileHandle {
|
||||
void *handle;
|
||||
};
|
||||
|
||||
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option);
|
||||
Result ReadFile(FileHandle handle, s64 offset, void *buffer, size_t size);
|
||||
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size, const fs::ReadOption &option);
|
||||
Result ReadFile(size_t *out, FileHandle handle, s64 offset, void *buffer, size_t size);
|
||||
Result GetFileSize(s64 *out, FileHandle handle);
|
||||
Result FlushFile(FileHandle handle);
|
||||
Result WriteFile(FileHandle handle, s64 offset, const void *buffer, size_t size, const fs::WriteOption &option);
|
||||
Result SetFileSize(FileHandle handle, s64 size);
|
||||
int GetFileOpenMode(FileHandle handle);
|
||||
void CloseFile(FileHandle handle);
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,12 @@
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
namespace fsa {
|
||||
|
||||
class IFile;
|
||||
|
||||
}
|
||||
|
||||
enum OpenMode {
|
||||
OpenMode_Read = ::FsOpenMode_Read,
|
||||
OpenMode_Write = ::FsOpenMode_Write,
|
||||
@@ -49,4 +55,27 @@ namespace ams::fs {
|
||||
|
||||
using FileTimeStampRaw = ::FsTimeStampRaw;
|
||||
|
||||
struct FileHandle;
|
||||
struct DirectoryHandle;
|
||||
|
||||
Result CreateFile(const char *path, s64 size);
|
||||
Result CreateFile(const char* path, s64 size, int option);
|
||||
Result DeleteFile(const char *path);
|
||||
Result CreateDirectory(const char *path);
|
||||
Result DeleteDirectory(const char *path);
|
||||
Result DeleteDirectoryRecursively(const char *path);
|
||||
Result RenameFile(const char *old_path, const char *new_path);
|
||||
Result RenameDirectory(const char *old_path, const char *new_path);
|
||||
Result GetEntryType(DirectoryEntryType *out, const char *path);
|
||||
Result OpenFile(FileHandle *out_file, const char *path, int mode);
|
||||
Result OpenDirectory(DirectoryHandle *out_dir, const char *path, int mode);
|
||||
Result CleanDirectoryRecursively(const char *path);
|
||||
Result GetFreeSpaceSize(s64 *out, const char *path);
|
||||
Result GetTotalSpaceSize(s64 *out, const char *path);
|
||||
|
||||
Result SetConcatenationFileAttribute(const char *path);
|
||||
Result GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path);
|
||||
|
||||
Result OpenFile(FileHandle *out, std::unique_ptr<fsa::IFile> &&file, int mode);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
enum class GameCardPartition {
|
||||
Update = 0,
|
||||
Normal = 1,
|
||||
Secure = 2,
|
||||
Logo = 3,
|
||||
};
|
||||
|
||||
enum class GameCardPartitionRaw {
|
||||
NormalReadable,
|
||||
SecureReadable,
|
||||
RootWriteable,
|
||||
};
|
||||
|
||||
enum class GameCardAttribute : u8 {
|
||||
AutoBootFlag = (1 << 0),
|
||||
HistoryEraseFlag = (1 << 1),
|
||||
RepairToolFlag = (1 << 2),
|
||||
DifferentRegionCupToTerraDeviceFlag = (1 << 3),
|
||||
DifferentRegionCupToGlobalDeviceFlag = (1 << 4),
|
||||
};
|
||||
|
||||
using GameCardHandle = u32;
|
||||
|
||||
Result GetGameCardHandle(GameCardHandle *out);
|
||||
Result MountGameCardPartition(const char *name, GameCardHandle handle, GameCardPartition partition);
|
||||
|
||||
}
|
||||
@@ -26,21 +26,15 @@ namespace ams::fs {
|
||||
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) = 0;
|
||||
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) = 0;
|
||||
|
||||
virtual Result Flush() = 0;
|
||||
|
||||
virtual Result SetSize(s64 size) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
virtual Result SetSize(s64 size) = 0;
|
||||
|
||||
virtual Result GetSize(s64 *out) = 0;
|
||||
|
||||
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) = 0;
|
||||
|
||||
virtual Result OperateRange(OperationId op_id, s64 offset, s64 size) {
|
||||
return this->OperateRange(nullptr, 0, op_id, offset, size, nullptr, 0);
|
||||
@@ -86,21 +80,31 @@ namespace ams::fs {
|
||||
|
||||
virtual ~ReadOnlyStorageAdapter() { /* ... */ }
|
||||
public:
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) {
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
||||
return this->storage->Read(offset, buffer, size);
|
||||
}
|
||||
|
||||
virtual Result Flush() {
|
||||
virtual Result Flush() override {
|
||||
return this->storage->Flush();
|
||||
}
|
||||
|
||||
virtual Result GetSize(s64 *out) {
|
||||
virtual Result GetSize(s64 *out) override {
|
||||
return this->storage->GetSize(out);
|
||||
}
|
||||
|
||||
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
|
||||
return this->storage->OperateRange(dst, dst_size, op_id, offset, size, src, src_size);
|
||||
}
|
||||
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
||||
/* TODO: Better result? Is it possible to get a more specific one? */
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result SetSize(s64 size) override {
|
||||
/* TODO: Better result? Is it possible to get a more specific one? */
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
using AllocateFunction = void *(*)(size_t);
|
||||
using DeallocateFunction = void (*)(void *, size_t);
|
||||
|
||||
void SetAllocator(AllocateFunction allocator, DeallocateFunction deallocator);
|
||||
|
||||
namespace impl {
|
||||
|
||||
void *Allocate(size_t size);
|
||||
void Deallocate(void *ptr, size_t size);
|
||||
|
||||
class Deleter {
|
||||
private:
|
||||
size_t size;
|
||||
public:
|
||||
Deleter() : size() { /* ... */ }
|
||||
explicit Deleter(size_t sz) : size(sz) { /* ... */ }
|
||||
|
||||
void operator()(void *ptr) const {
|
||||
::ams::fs::impl::Deallocate(ptr, this->size);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
std::unique_ptr<T, Deleter> MakeUnique() {
|
||||
static_assert(std::is_pod<T>::value);
|
||||
return std::unique_ptr<T, Deleter>(static_cast<T *>(::ams::fs::impl::Allocate(sizeof(T))), Deleter(sizeof(T)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "impl/fs_newable.hpp"
|
||||
#include "fs_istorage.hpp"
|
||||
#include "fs_query_range.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
class MemoryStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable {
|
||||
private:
|
||||
u8 * const buf;
|
||||
const s64 size;
|
||||
public:
|
||||
MemoryStorage(void *b, s64 sz) : buf(static_cast<u8 *>(b)), size(sz) { /* .. */ }
|
||||
public:
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
||||
/* Succeed immediately on zero-sized read. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Validate arguments. */
|
||||
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
|
||||
R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange());
|
||||
|
||||
/* Copy from memory. */
|
||||
std::memcpy(buffer, this->buf + offset, size);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
||||
/* Succeed immediately on zero-sized write. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Validate arguments. */
|
||||
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
|
||||
R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange());
|
||||
|
||||
/* Copy to memory. */
|
||||
std::memcpy(this->buf + offset, buffer, size);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result GetSize(s64 *out) override {
|
||||
*out = this->size;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result SetSize(s64 size) override {
|
||||
return fs::ResultUnsupportedOperationInMemoryStorageA();
|
||||
}
|
||||
|
||||
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
|
||||
switch (op_id) {
|
||||
case OperationId::InvalidateCache:
|
||||
return ResultSuccess();
|
||||
case OperationId::QueryRange:
|
||||
R_UNLESS(dst != nullptr, fs::ResultNullptrArgument());
|
||||
R_UNLESS(dst_size == sizeof(QueryRangeInfo), fs::ResultInvalidSize());
|
||||
reinterpret_cast<QueryRangeInfo *>(dst)->Clear();
|
||||
return ResultSuccess();
|
||||
default:
|
||||
return fs::ResultUnsupportedOperationInMemoryStorageB();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
constexpr inline size_t MountNameLengthMax = 15;
|
||||
|
||||
Result ConvertToFsCommonPath(char *dst, size_t dst_size, const char *src);
|
||||
|
||||
void Unmount(const char *mount_name);
|
||||
|
||||
}
|
||||
@@ -26,16 +26,25 @@ namespace ams::fs {
|
||||
constexpr inline char Dot = '.';
|
||||
constexpr inline char NullTerminator = '\x00';
|
||||
|
||||
constexpr inline char AlternateDirectorySeparator = '\\';
|
||||
}
|
||||
|
||||
class PathTool {
|
||||
public:
|
||||
static constexpr const char RootPath[] = "/";
|
||||
public:
|
||||
static constexpr inline bool IsAlternateSeparator(char c) {
|
||||
return c == StringTraits::AlternateDirectorySeparator;
|
||||
}
|
||||
|
||||
static constexpr inline bool IsSeparator(char c) {
|
||||
return c == StringTraits::DirectorySeparator;
|
||||
}
|
||||
|
||||
static constexpr inline bool IsAnySeparator(char c) {
|
||||
return IsSeparator(c) || IsAlternateSeparator(c);
|
||||
}
|
||||
|
||||
static constexpr inline bool IsNullTerminator(char c) {
|
||||
return c == StringTraits::NullTerminator;
|
||||
}
|
||||
@@ -56,6 +65,10 @@ namespace ams::fs {
|
||||
return IsWindowsDriveCharacter(p[0]) && IsDriveSeparator(p[1]);
|
||||
}
|
||||
|
||||
static constexpr inline bool IsUnc(const char *p) {
|
||||
return (IsSeparator(p[0]) && IsSeparator(p[1])) || (IsAlternateSeparator(p[0]) && IsAlternateSeparator(p[1]));
|
||||
}
|
||||
|
||||
static constexpr inline bool IsCurrentDirectory(const char *p) {
|
||||
return IsDot(p[0]) && (IsSeparator(p[1]) || IsNullTerminator(p[1]));
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
#include "fs_file.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
@@ -42,4 +43,6 @@ namespace ams::fs {
|
||||
using FileQueryRangeInfo = QueryRangeInfo;
|
||||
using StorageQueryRangeInfo = QueryRangeInfo;
|
||||
|
||||
Result QueryRange(QueryRangeInfo *out, FileHandle handle, s64 offset, s64 size);
|
||||
|
||||
}
|
||||
|
||||
@@ -14,165 +14,217 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
#include "fsa/fs_ifile.hpp"
|
||||
#include "fsa/fs_idirectory.hpp"
|
||||
#include "fsa/fs_ifilesystem.hpp"
|
||||
#include <stratosphere/fs/fs_common.hpp>
|
||||
#include <stratosphere/fs/impl/fs_newable.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifile.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_idirectory.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
|
||||
#include <stratosphere/fs/fs_query_range.hpp>
|
||||
#include <stratosphere/fs/fs_path_tool.hpp>
|
||||
#include <stratosphere/fs/fs_path_utils.hpp>
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
class RemoteFile : public fsa::IFile {
|
||||
class RemoteFile : public fsa::IFile, public impl::Newable {
|
||||
private:
|
||||
std::unique_ptr<::FsFile> base_file;
|
||||
::FsFile base_file;
|
||||
public:
|
||||
RemoteFile(::FsFile *f) : base_file(f) { /* ... */ }
|
||||
RemoteFile(std::unique_ptr<::FsFile> f) : base_file(std::move(f)) { /* ... */ }
|
||||
RemoteFile(::FsFile f) {
|
||||
this->base_file = std::make_unique<::FsFile>(f);
|
||||
}
|
||||
RemoteFile(const ::FsFile &f) : base_file(f) { /* ... */ }
|
||||
|
||||
virtual ~RemoteFile() { fsFileClose(this->base_file.get()); }
|
||||
virtual ~RemoteFile() { fsFileClose(std::addressof(this->base_file)); }
|
||||
public:
|
||||
virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override final {
|
||||
return fsFileRead(this->base_file.get(), offset, buffer, size, option.value, out);
|
||||
return fsFileRead(std::addressof(this->base_file), offset, buffer, size, option.value, out);
|
||||
}
|
||||
|
||||
virtual Result GetSizeImpl(s64 *out) override final {
|
||||
return fsFileGetSize(this->base_file.get(), out);
|
||||
return fsFileGetSize(std::addressof(this->base_file), out);
|
||||
}
|
||||
|
||||
virtual Result FlushImpl() override final {
|
||||
return fsFileFlush(this->base_file.get());
|
||||
return fsFileFlush(std::addressof(this->base_file));
|
||||
}
|
||||
|
||||
virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override final {
|
||||
return fsFileWrite(this->base_file.get(), offset, buffer, size, option.value);
|
||||
return fsFileWrite(std::addressof(this->base_file), offset, buffer, size, option.value);
|
||||
}
|
||||
|
||||
virtual Result SetSizeImpl(s64 size) override final {
|
||||
return fsFileSetSize(this->base_file.get(), size);
|
||||
return fsFileSetSize(std::addressof(this->base_file), size);
|
||||
}
|
||||
|
||||
virtual Result OperateRangeImpl(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override final {
|
||||
/* TODO: How should this be handled? */
|
||||
return fs::ResultNotImplemented();
|
||||
R_UNLESS(op_id == OperationId::QueryRange, fs::ResultUnsupportedOperationInFileServiceObjectAdapterA());
|
||||
R_UNLESS(dst_size == sizeof(FileQueryRangeInfo), fs::ResultInvalidSize());
|
||||
|
||||
return fsFileOperateRange(std::addressof(this->base_file), static_cast<::FsOperationId>(op_id), offset, size, reinterpret_cast<::FsRangeInfo *>(dst));
|
||||
}
|
||||
public:
|
||||
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override {
|
||||
return sf::cmif::DomainObjectId{serviceGetObjectId(&this->base_file->s)};
|
||||
return sf::cmif::DomainObjectId{serviceGetObjectId(const_cast<::Service *>(std::addressof(this->base_file.s)))};
|
||||
}
|
||||
};
|
||||
|
||||
class RemoteDirectory : public fsa::IDirectory {
|
||||
class RemoteDirectory : public fsa::IDirectory, public impl::Newable {
|
||||
private:
|
||||
std::unique_ptr<::FsDir> base_dir;
|
||||
::FsDir base_dir;
|
||||
public:
|
||||
RemoteDirectory(::FsDir *d) : base_dir(d) { /* ... */ }
|
||||
RemoteDirectory(std::unique_ptr<::FsDir> d) : base_dir(std::move(d)) { /* ... */ }
|
||||
RemoteDirectory(::FsDir d) {
|
||||
this->base_dir = std::make_unique<::FsDir>(d);
|
||||
}
|
||||
RemoteDirectory(const ::FsDir &d) : base_dir(d) { /* ... */ }
|
||||
|
||||
virtual ~RemoteDirectory() { fsDirClose(this->base_dir.get()); }
|
||||
virtual ~RemoteDirectory() { fsDirClose(std::addressof(this->base_dir)); }
|
||||
public:
|
||||
virtual Result ReadImpl(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) override final {
|
||||
return fsDirRead(this->base_dir.get(), out_count, max_entries, out_entries);
|
||||
return fsDirRead(std::addressof(this->base_dir), out_count, max_entries, out_entries);
|
||||
}
|
||||
|
||||
virtual Result GetEntryCountImpl(s64 *out) override final {
|
||||
return fsDirGetEntryCount(this->base_dir.get(), out);
|
||||
return fsDirGetEntryCount(std::addressof(this->base_dir), out);
|
||||
}
|
||||
public:
|
||||
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override {
|
||||
return sf::cmif::DomainObjectId{serviceGetObjectId(&this->base_dir->s)};
|
||||
return sf::cmif::DomainObjectId{serviceGetObjectId(const_cast<::Service *>(std::addressof(this->base_dir.s)))};
|
||||
}
|
||||
};
|
||||
|
||||
class RemoteFileSystem : public fsa::IFileSystem {
|
||||
class RemoteFileSystem : public fsa::IFileSystem, public impl::Newable {
|
||||
private:
|
||||
std::unique_ptr<::FsFileSystem> base_fs;
|
||||
::FsFileSystem base_fs;
|
||||
public:
|
||||
RemoteFileSystem(::FsFileSystem *fs) : base_fs(fs) { /* ... */ }
|
||||
RemoteFileSystem(std::unique_ptr<::FsFileSystem> fs) : base_fs(std::move(fs)) { /* ... */ }
|
||||
RemoteFileSystem(::FsFileSystem fs) {
|
||||
this->base_fs = std::make_unique<::FsFileSystem>(fs);
|
||||
}
|
||||
RemoteFileSystem(const ::FsFileSystem &fs) : base_fs(fs) { /* ... */ }
|
||||
|
||||
virtual ~RemoteFileSystem() { fsFsClose(this->base_fs.get()); }
|
||||
virtual ~RemoteFileSystem() { fsFsClose(std::addressof(this->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';
|
||||
|
||||
/* Replace directory separators. */
|
||||
Replace(out_path->str, sizeof(out_path->str) - 1, StringTraits::AlternateDirectorySeparator, StringTraits::DirectorySeparator);
|
||||
|
||||
/* Get lengths. */
|
||||
const auto mount_name_len = PathTool::IsWindowsAbsolutePath(path) ? 2 : 0;
|
||||
const auto rel_path = out_path->str + mount_name_len;
|
||||
const auto max_len = fs::EntryNameLengthMax - mount_name_len;
|
||||
return VerifyPath(rel_path, max_len, max_len);
|
||||
}
|
||||
public:
|
||||
virtual Result CreateFileImpl(const char *path, s64 size, int flags) override final {
|
||||
return fsFsCreateFile(this->base_fs.get(), path, size, flags);
|
||||
fssrv::sf::Path sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
|
||||
return fsFsCreateFile(std::addressof(this->base_fs), sf_path.str, size, flags);
|
||||
}
|
||||
|
||||
virtual Result DeleteFileImpl(const char *path) override final {
|
||||
return fsFsDeleteFile(this->base_fs.get(), path);
|
||||
fssrv::sf::Path sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
|
||||
return fsFsDeleteFile(std::addressof(this->base_fs), sf_path.str);
|
||||
}
|
||||
|
||||
virtual Result CreateDirectoryImpl(const char *path) override final {
|
||||
return fsFsCreateDirectory(this->base_fs.get(), path);
|
||||
fssrv::sf::Path sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
|
||||
return fsFsCreateDirectory(std::addressof(this->base_fs), sf_path.str);
|
||||
}
|
||||
|
||||
virtual Result DeleteDirectoryImpl(const char *path) override final {
|
||||
return fsFsDeleteDirectory(this->base_fs.get(), path);
|
||||
fssrv::sf::Path sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
|
||||
return fsFsDeleteDirectory(std::addressof(this->base_fs), sf_path.str);
|
||||
}
|
||||
|
||||
virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override final {
|
||||
return fsFsDeleteDirectoryRecursively(this->base_fs.get(), path);
|
||||
fssrv::sf::Path sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
|
||||
return fsFsDeleteDirectoryRecursively(std::addressof(this->base_fs), sf_path.str);
|
||||
}
|
||||
|
||||
virtual Result RenameFileImpl(const char *old_path, const char *new_path) override final {
|
||||
return fsFsRenameFile(this->base_fs.get(), old_path, new_path);
|
||||
fssrv::sf::Path old_sf_path;
|
||||
fssrv::sf::Path new_sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(old_sf_path), old_path));
|
||||
R_TRY(GetPathForServiceObject(std::addressof(new_sf_path), new_path));
|
||||
return fsFsRenameFile(std::addressof(this->base_fs), old_sf_path.str, new_sf_path.str);
|
||||
}
|
||||
|
||||
virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override final {
|
||||
return fsFsRenameDirectory(this->base_fs.get(), old_path, new_path);
|
||||
fssrv::sf::Path old_sf_path;
|
||||
fssrv::sf::Path new_sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(old_sf_path), old_path));
|
||||
R_TRY(GetPathForServiceObject(std::addressof(new_sf_path), new_path));
|
||||
return fsFsRenameDirectory(std::addressof(this->base_fs), old_sf_path.str, new_sf_path.str);
|
||||
}
|
||||
|
||||
virtual Result GetEntryTypeImpl(DirectoryEntryType *out, const char *path) override final {
|
||||
fssrv::sf::Path sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
|
||||
|
||||
static_assert(sizeof(::FsDirEntryType) == sizeof(DirectoryEntryType));
|
||||
return fsFsGetEntryType(this->base_fs.get(), path, reinterpret_cast<::FsDirEntryType *>(out));
|
||||
return fsFsGetEntryType(std::addressof(this->base_fs), sf_path.str, reinterpret_cast<::FsDirEntryType *>(out));
|
||||
}
|
||||
|
||||
virtual Result OpenFileImpl(std::unique_ptr<fsa::IFile> *out_file, const char *path, OpenMode mode) override final {
|
||||
FsFile f;
|
||||
R_TRY(fsFsOpenFile(this->base_fs.get(), path, mode, &f));
|
||||
fssrv::sf::Path sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
|
||||
|
||||
*out_file = std::make_unique<RemoteFile>(f);
|
||||
FsFile f;
|
||||
R_TRY(fsFsOpenFile(std::addressof(this->base_fs), sf_path.str, mode, &f));
|
||||
|
||||
auto file = std::make_unique<RemoteFile>(f);
|
||||
R_UNLESS(file != nullptr, fs::ResultAllocationFailureInNew());
|
||||
|
||||
*out_file = std::move(file);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result OpenDirectoryImpl(std::unique_ptr<fsa::IDirectory> *out_dir, const char *path, OpenDirectoryMode mode) override final {
|
||||
FsDir d;
|
||||
R_TRY(fsFsOpenDirectory(this->base_fs.get(), path, mode, &d));
|
||||
fssrv::sf::Path sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
|
||||
|
||||
*out_dir = std::make_unique<RemoteDirectory>(d);
|
||||
FsDir d;
|
||||
R_TRY(fsFsOpenDirectory(std::addressof(this->base_fs), sf_path.str, mode, &d));
|
||||
|
||||
auto dir = std::make_unique<RemoteDirectory>(d);
|
||||
R_UNLESS(dir != nullptr, fs::ResultAllocationFailureInNew());
|
||||
|
||||
*out_dir = std::move(dir);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result CommitImpl() override final {
|
||||
return fsFsCommit(this->base_fs.get());
|
||||
return fsFsCommit(std::addressof(this->base_fs));
|
||||
}
|
||||
|
||||
|
||||
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) {
|
||||
return fsFsGetFreeSpace(this->base_fs.get(), path, out);
|
||||
fssrv::sf::Path sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
|
||||
return fsFsGetFreeSpace(std::addressof(this->base_fs), sf_path.str, out);
|
||||
}
|
||||
|
||||
virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) {
|
||||
return fsFsGetTotalSpace(this->base_fs.get(), path, out);
|
||||
fssrv::sf::Path sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
|
||||
return fsFsGetTotalSpace(std::addressof(this->base_fs), sf_path.str, out);
|
||||
}
|
||||
|
||||
virtual Result CleanDirectoryRecursivelyImpl(const char *path) {
|
||||
return fsFsCleanDirectoryRecursively(this->base_fs.get(), path);
|
||||
fssrv::sf::Path sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
|
||||
return fsFsCleanDirectoryRecursively(std::addressof(this->base_fs), sf_path.str);
|
||||
}
|
||||
|
||||
virtual Result GetFileTimeStampRawImpl(FileTimeStampRaw *out, const char *path) {
|
||||
fssrv::sf::Path sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
|
||||
static_assert(sizeof(FileTimeStampRaw) == sizeof(::FsTimeStampRaw));
|
||||
return fsFsGetFileTimeStampRaw(this->base_fs.get(), path, reinterpret_cast<::FsTimeStampRaw *>(out));
|
||||
return fsFsGetFileTimeStampRaw(std::addressof(this->base_fs), sf_path.str, reinterpret_cast<::FsTimeStampRaw *>(out));
|
||||
}
|
||||
|
||||
virtual Result QueryEntryImpl(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path) {
|
||||
return fsFsQueryEntry(this->base_fs.get(), dst, dst_size, src, src_size, path, static_cast<FsFileSystemQueryId>(query));
|
||||
fssrv::sf::Path sf_path;
|
||||
R_TRY(GetPathForServiceObject(std::addressof(sf_path), path));
|
||||
return fsFsQueryEntry(std::addressof(this->base_fs), dst, dst_size, src, src_size, sf_path.str, static_cast<FsFileSystemQueryId>(query));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -16,17 +16,17 @@
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
#include "fs_istorage.hpp"
|
||||
#include "impl/fs_newable.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
class RemoteStorage : public IStorage {
|
||||
class RemoteStorage : public IStorage, public impl::Newable {
|
||||
private:
|
||||
std::unique_ptr<::FsStorage> base_storage;
|
||||
std::unique_ptr<::FsStorage, impl::Deleter> base_storage;
|
||||
public:
|
||||
RemoteStorage(::FsStorage *s) : base_storage(s) { /* ... */ }
|
||||
RemoteStorage(std::unique_ptr<::FsStorage> s) : base_storage(std::move(s)) { /* ... */ }
|
||||
RemoteStorage(::FsStorage s) {
|
||||
this->base_storage = std::make_unique<::FsStorage>(s);
|
||||
RemoteStorage(::FsStorage &s) {
|
||||
this->base_storage = impl::MakeUnique<::FsStorage>();
|
||||
*this->base_storage = s;
|
||||
}
|
||||
|
||||
virtual ~RemoteStorage() { fsStorageClose(this->base_storage.get()); }
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
union RightsId {
|
||||
u8 data[0x10];
|
||||
u64 data64[2];
|
||||
};
|
||||
static_assert(sizeof(RightsId) == 0x10);
|
||||
static_assert(std::is_pod<RightsId>::value);
|
||||
|
||||
/* Rights ID API */
|
||||
Result GetRightsId(RightsId *out, const char *path);
|
||||
Result GetRightsId(RightsId *out, u8 *out_key_generation, const char *path);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
#include "impl/fs_newable.hpp"
|
||||
#include "fsa/fs_ifile.hpp"
|
||||
#include "fsa/fs_idirectory.hpp"
|
||||
#include "fsa/fs_ifilesystem.hpp"
|
||||
#include "fs_dbm_hierarchical_rom_file_table.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
class RomFsFileSystem : public fsa::IFileSystem, public impl::Newable {
|
||||
NON_COPYABLE(RomFsFileSystem);
|
||||
public:
|
||||
using RomFileTable = HierarchicalRomFileTable;
|
||||
private:
|
||||
RomFileTable rom_file_table;
|
||||
IStorage *base_storage;
|
||||
std::unique_ptr<IStorage> unique_storage;
|
||||
std::unique_ptr<IStorage> dir_bucket_storage;
|
||||
std::unique_ptr<IStorage> dir_entry_storage;
|
||||
std::unique_ptr<IStorage> file_bucket_storage;
|
||||
std::unique_ptr<IStorage> file_entry_storage;
|
||||
s64 entry_size;
|
||||
private:
|
||||
Result GetFileInfo(RomFileTable::FileInfo *out, const char *path);
|
||||
public:
|
||||
static Result GetRequiredWorkingMemorySize(size_t *out, IStorage *storage);
|
||||
public:
|
||||
RomFsFileSystem();
|
||||
virtual ~RomFsFileSystem() override;
|
||||
|
||||
Result Initialize(IStorage *base, void *work, size_t work_size, bool use_cache);
|
||||
Result Initialize(std::unique_ptr<IStorage>&& base, void *work, size_t work_size, bool use_cache);
|
||||
|
||||
IStorage *GetBaseStorage();
|
||||
RomFileTable *GetRomFileTable();
|
||||
Result GetFileBaseOffset(s64 *out, const char *path);
|
||||
public:
|
||||
virtual Result CreateFileImpl(const char *path, s64 size, int flags) override;
|
||||
virtual Result DeleteFileImpl(const char *path) override;
|
||||
virtual Result CreateDirectoryImpl(const char *path) override;
|
||||
virtual Result DeleteDirectoryImpl(const char *path) override;
|
||||
virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override;
|
||||
virtual Result RenameFileImpl(const char *old_path, const char *new_path) override;
|
||||
virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override;
|
||||
virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) override;
|
||||
virtual Result OpenFileImpl(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) override;
|
||||
virtual Result OpenDirectoryImpl(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) override;
|
||||
virtual Result CommitImpl() override;
|
||||
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override;
|
||||
virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override;
|
||||
virtual Result CleanDirectoryRecursivelyImpl(const char *path) override;
|
||||
|
||||
/* These aren't accessible as commands. */
|
||||
virtual Result CommitProvisionallyImpl(s64 counter) override;
|
||||
virtual Result RollbackImpl() override;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
#include "fs_save_data_types.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
Result DeleteSaveData(SaveDataId id);
|
||||
Result DeleteSaveData(SaveDataSpaceId space_id, SaveDataId id);
|
||||
|
||||
Result GetSaveDataFlags(u32 *out, SaveDataId id);
|
||||
Result GetSaveDataFlags(u32 *out, SaveDataSpaceId space_id, SaveDataId id);
|
||||
Result SetSaveDataFlags(SaveDataId id, SaveDataSpaceId space_id, u32 flags);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
#include "fs_save_data_types.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
Result CommitSaveData(const char *path);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
using SaveDataId = u64;
|
||||
using SystemSaveDataId = u64;
|
||||
using SystemBcatSaveDataId = SystemSaveDataId;
|
||||
|
||||
enum class SaveDataSpaceId : u8 {
|
||||
System = 0,
|
||||
User = 1,
|
||||
SdSystem = 2,
|
||||
Temporary = 3,
|
||||
SdUser = 4,
|
||||
|
||||
ProperSystem = 100,
|
||||
SafeMode = 101,
|
||||
};
|
||||
|
||||
enum class SaveDataType : u8 {
|
||||
System = 0,
|
||||
Account = 1,
|
||||
Bcat = 2,
|
||||
Device = 3,
|
||||
Temporary = 4,
|
||||
Cache = 5,
|
||||
SystemBcat = 6,
|
||||
};
|
||||
|
||||
enum class SaveDataRank : u8 {
|
||||
Primary = 0,
|
||||
Secondary = 1,
|
||||
};
|
||||
|
||||
struct UserId {
|
||||
u64 data[2];
|
||||
};
|
||||
static_assert(std::is_pod<UserId>::value);
|
||||
|
||||
constexpr inline bool operator<(const UserId &lhs, const UserId &rhs) {
|
||||
if (lhs.data[0] < rhs.data[0]) {
|
||||
return true;
|
||||
} else if (lhs.data[0] == rhs.data[0] && lhs.data[1] < rhs.data[1]) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr inline bool operator==(const UserId &lhs, const UserId &rhs) {
|
||||
return lhs.data[0] == rhs.data[0] && lhs.data[1] == rhs.data[1];
|
||||
}
|
||||
|
||||
constexpr inline bool operator!=(const UserId &lhs, const UserId &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
constexpr inline SystemSaveDataId InvalidSystemSaveDataId = 0;
|
||||
constexpr inline UserId InvalidUserId = {};
|
||||
|
||||
enum SaveDataFlags : u32 {
|
||||
SaveDataFlags_None = (0 << 0),
|
||||
SaveDataFlags_KeepAfterResettingSystemSaveData = (1 << 0),
|
||||
SaveDataFlags_KeepAfterRefurbishment = (1 << 1),
|
||||
SaveDataFlags_KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
|
||||
SaveDataFlags_NeedsSecureDelete = (1 << 3),
|
||||
};
|
||||
|
||||
struct SaveDataCreationInfo {
|
||||
s64 size;
|
||||
s64 journal_size;
|
||||
s64 block_size;
|
||||
u64 owner_id;
|
||||
u32 flags;
|
||||
SaveDataSpaceId space_id;
|
||||
bool pseudo;
|
||||
u8 reserved[0x1A];
|
||||
};
|
||||
static_assert(std::is_pod<SaveDataCreationInfo>::value);
|
||||
static_assert(sizeof(SaveDataCreationInfo) == 0x40);
|
||||
|
||||
struct SaveDataAttribute {
|
||||
ncm::ProgramId program_id;
|
||||
UserId user_id;
|
||||
SystemSaveDataId system_save_data_id;
|
||||
SaveDataType type;
|
||||
SaveDataRank rank;
|
||||
u16 index;
|
||||
u8 reserved[0x1C];
|
||||
|
||||
static constexpr SaveDataAttribute Make(ncm::ProgramId program_id, SaveDataType type, UserId user_id, SystemSaveDataId system_save_data_id, u16 index, SaveDataRank rank) {
|
||||
return {
|
||||
.program_id = program_id,
|
||||
.user_id = user_id,
|
||||
.system_save_data_id = system_save_data_id,
|
||||
.type = type,
|
||||
.rank = rank,
|
||||
.index = index,
|
||||
};
|
||||
}
|
||||
|
||||
static constexpr SaveDataAttribute Make(ncm::ProgramId program_id, SaveDataType type, UserId user_id, SystemSaveDataId system_save_data_id, u16 index) {
|
||||
return Make(program_id, type, user_id, system_save_data_id, index, SaveDataRank::Primary);
|
||||
}
|
||||
|
||||
static constexpr SaveDataAttribute Make(ncm::ProgramId program_id, SaveDataType type, UserId user_id, SystemSaveDataId system_save_data_id) {
|
||||
return Make(program_id, type, user_id, system_save_data_id, 0, SaveDataRank::Primary);
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(SaveDataAttribute) == 0x40);
|
||||
static_assert(std::is_trivially_destructible<SaveDataAttribute>::value);
|
||||
|
||||
constexpr inline bool operator<(const SaveDataAttribute &lhs, const SaveDataAttribute &rhs) {
|
||||
return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.index, lhs.rank) <
|
||||
std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id, rhs.index, rhs.rank);
|
||||
}
|
||||
|
||||
constexpr inline bool operator==(const SaveDataAttribute &lhs, const SaveDataAttribute &rhs) {
|
||||
return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.type, lhs.rank, lhs.index) ==
|
||||
std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id, rhs.type, rhs.rank, rhs.index);
|
||||
}
|
||||
|
||||
constexpr inline bool operator!=(const SaveDataAttribute &lhs, const SaveDataAttribute &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
constexpr inline size_t DefaultSaveDataBlockSize = 16_KB;
|
||||
|
||||
struct SaveDataExtraData {
|
||||
SaveDataAttribute attr;
|
||||
u64 owner_id;
|
||||
s64 timestamp;
|
||||
u32 flags;
|
||||
u8 pad[4];
|
||||
s64 available_size;
|
||||
s64 journal_size;
|
||||
s64 commit_id;
|
||||
u8 unused[0x190];
|
||||
};
|
||||
static_assert(sizeof(SaveDataExtraData) == 0x200);
|
||||
static_assert(std::is_pod<SaveDataExtraData>::value);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
Result MountSdCard(const char *name);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
bool IsSignedSystemPartitionOnSdCardValid(const char *system_root_path);
|
||||
bool IsSignedSystemPartitionOnSdCardValidDeprecated();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "impl/fs_newable.hpp"
|
||||
#include "fs_istorage.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
class SubStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable {
|
||||
private:
|
||||
std::shared_ptr<IStorage> shared_base_storage;
|
||||
fs::IStorage *base_storage;
|
||||
s64 offset;
|
||||
s64 size;
|
||||
bool resizable;
|
||||
private:
|
||||
constexpr bool IsValid() const {
|
||||
return this->base_storage != nullptr;
|
||||
}
|
||||
public:
|
||||
SubStorage() : shared_base_storage(), base_storage(nullptr), offset(0), size(0), resizable(false) { /* ... */ }
|
||||
|
||||
SubStorage(const SubStorage &rhs) : shared_base_storage(), base_storage(rhs.base_storage), offset(rhs.offset), size(rhs.size), resizable(rhs.resizable) { /* ... */}
|
||||
SubStorage &operator=(const SubStorage &rhs) {
|
||||
if (this != std::addressof(rhs)) {
|
||||
this->base_storage = rhs.base_storage;
|
||||
this->offset = rhs.offset;
|
||||
this->size = rhs.size;
|
||||
this->resizable = rhs.resizable;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
SubStorage(IStorage *storage, s64 o, s64 sz) : shared_base_storage(), base_storage(storage), offset(o), size(sz) {
|
||||
AMS_ABORT_UNLESS(this->IsValid());
|
||||
AMS_ABORT_UNLESS(this->offset >= 0);
|
||||
AMS_ABORT_UNLESS(this->size >= 0);
|
||||
}
|
||||
|
||||
SubStorage(std::shared_ptr<IStorage> storage, s64 o, s64 sz) : shared_base_storage(storage), base_storage(storage.get()), offset(o), size(sz) {
|
||||
AMS_ABORT_UNLESS(this->IsValid());
|
||||
AMS_ABORT_UNLESS(this->offset >= 0);
|
||||
AMS_ABORT_UNLESS(this->size >= 0);
|
||||
}
|
||||
|
||||
SubStorage(SubStorage *sub, s64 o, s64 sz) : shared_base_storage(), base_storage(sub->base_storage), offset(o + sub->offset), size(sz) {
|
||||
AMS_ABORT_UNLESS(this->IsValid());
|
||||
AMS_ABORT_UNLESS(this->offset >= 0);
|
||||
AMS_ABORT_UNLESS(this->size >= 0);
|
||||
AMS_ABORT_UNLESS(sub->size >= o + sz);
|
||||
}
|
||||
|
||||
public:
|
||||
void SetResizable(bool rsz) {
|
||||
this->resizable = rsz;
|
||||
}
|
||||
public:
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
||||
/* Ensure we're initialized. */
|
||||
R_UNLESS(this->IsValid(), fs::ResultNotInitialized());
|
||||
|
||||
/* Succeed immediately on zero-sized operation. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
|
||||
/* Validate arguments and read. */
|
||||
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
|
||||
R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange());
|
||||
return this->base_storage->Read(this->offset + offset, buffer, size);
|
||||
}
|
||||
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override{
|
||||
/* Ensure we're initialized. */
|
||||
R_UNLESS(this->IsValid(), fs::ResultNotInitialized());
|
||||
|
||||
/* Succeed immediately on zero-sized operation. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Validate arguments and write. */
|
||||
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
|
||||
R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange());
|
||||
return this->base_storage->Write(this->offset + offset, buffer, size);
|
||||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
R_UNLESS(this->IsValid(), fs::ResultNotInitialized());
|
||||
return this->base_storage->Flush();
|
||||
}
|
||||
|
||||
virtual Result SetSize(s64 size) override {
|
||||
/* Ensure we're initialized and validate arguments. */
|
||||
R_UNLESS(this->IsValid(), fs::ResultNotInitialized());
|
||||
R_UNLESS(this->resizable, fs::ResultUnsupportedOperationInSubStorageA());
|
||||
R_UNLESS(IStorage::IsOffsetAndSizeValid(this->offset, size), fs::ResultInvalidSize());
|
||||
|
||||
/* Ensure that we're allowed to set size. */
|
||||
s64 cur_size;
|
||||
R_TRY(this->base_storage->GetSize(std::addressof(cur_size)));
|
||||
R_UNLESS(cur_size == this->offset + this->size, fs::ResultUnsupportedOperationInSubStorageB());
|
||||
|
||||
/* Set the size. */
|
||||
R_TRY(this->base_storage->SetSize(this->offset + size));
|
||||
|
||||
this->size = size;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result GetSize(s64 *out) override {
|
||||
/* Ensure we're initialized. */
|
||||
R_UNLESS(this->IsValid(), fs::ResultNotInitialized());
|
||||
|
||||
*out = this->size;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
|
||||
/* Ensure we're initialized. */
|
||||
R_UNLESS(this->IsValid(), fs::ResultNotInitialized());
|
||||
|
||||
/* Succeed immediately on zero-sized operation. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Validate arguments and operate. */
|
||||
R_UNLESS(IStorage::IsOffsetAndSizeValid(offset, size), fs::ResultOutOfRange());
|
||||
return this->base_storage->OperateRange(dst, dst_size, op_id, this->offset + offset, size, src, src_size);
|
||||
}
|
||||
|
||||
using IStorage::OperateRange;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
Result QueryMountSystemDataCacheSize(size_t *out, ncm::SystemDataId data_id);
|
||||
|
||||
Result MountSystemData(const char *name, ncm::SystemDataId data_id);
|
||||
Result MountSystemData(const char *name, ncm::SystemDataId data_id, void *cache_buffer, size_t cache_size);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
#include "fs_save_data_types.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
void DisableAutoSaveDataCreation();
|
||||
|
||||
Result CreateSystemSaveData(SystemSaveDataId save_id, s64 size, s64 journal_size, u32 flags);
|
||||
Result CreateSystemSaveData(SystemSaveDataId save_id, u64 owner_id, s64 size, s64 journal_size, u32 flags);
|
||||
Result CreateSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId save_id, u64 owner_id, s64 size, s64 journal_size, u32 flags);
|
||||
|
||||
Result CreateSystemSaveData(SystemSaveDataId save_id, UserId user_id, s64 size, s64 journal_size, u32 flags);
|
||||
Result CreateSystemSaveData(SystemSaveDataId save_id, UserId user_id, u64 owner_id, s64 size, s64 journal_size, u32 flags);
|
||||
Result CreateSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId save_id, UserId user_id, u64 owner_id, s64 size, s64 journal_size, u32 flags);
|
||||
|
||||
Result MountSystemSaveData(const char *name, SystemSaveDataId id);
|
||||
Result MountSystemSaveData(const char *name, SaveDataSpaceId space_id, SystemSaveDataId id);
|
||||
|
||||
Result MountSystemSaveData(const char *name, SystemSaveDataId id, UserId user_id);
|
||||
Result MountSystemSaveData(const char *name, SaveDataSpaceId space_id, SystemSaveDataId id, UserId user_id);
|
||||
|
||||
Result DeleteSystemSaveData(SaveDataSpaceId space_id, SystemSaveDataId id, UserId user_id);
|
||||
|
||||
}
|
||||
@@ -96,10 +96,12 @@ namespace ams::fs::fsa {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result DrySetSize(s64 size, OpenMode open_mode) {
|
||||
Result DrySetSize(s64 size, fs::OpenMode open_mode) {
|
||||
/* Check that we can write. */
|
||||
R_UNLESS((open_mode & OpenMode_Write) != 0, fs::ResultInvalidOperationForOpenMode());
|
||||
|
||||
AMS_ASSERT(size >= 0);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
private:
|
||||
|
||||
@@ -24,7 +24,8 @@ namespace ams::fs::fsa {
|
||||
class IDirectory;
|
||||
|
||||
enum class QueryId {
|
||||
SetConcatenationFileAttribute = FsFileSystemQueryId_SetConcatenationFileAttribute
|
||||
SetConcatenationFileAttribute = 0,
|
||||
IsSignedSystemPartitionOnSdCardValid = 2,
|
||||
};
|
||||
|
||||
class IFileSystem {
|
||||
@@ -88,10 +89,10 @@ namespace ams::fs::fsa {
|
||||
}
|
||||
|
||||
Result OpenDirectory(std::unique_ptr<IDirectory> *out_dir, const char *path, OpenDirectoryMode mode) {
|
||||
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
|
||||
R_UNLESS(out_dir != nullptr, fs::ResultNullptrArgument());
|
||||
R_UNLESS((mode & OpenDirectoryMode_All) != 0, fs::ResultInvalidArgument());
|
||||
R_UNLESS((mode & ~OpenDirectoryMode_All) == 0, fs::ResultInvalidArgument());
|
||||
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
|
||||
R_UNLESS(out_dir != nullptr, fs::ResultNullptrArgument());
|
||||
R_UNLESS((mode & OpenDirectoryMode_All) != 0, fs::ResultInvalidArgument());
|
||||
R_UNLESS((mode & ~(OpenDirectoryMode_All | OpenDirectoryMode_NotRequireFileSize)) == 0, fs::ResultInvalidArgument());
|
||||
return this->OpenDirectoryImpl(out_dir, path, mode);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../fs_common.hpp"
|
||||
|
||||
namespace ams::fs::fsa {
|
||||
|
||||
class ICommonMountNameGenerator {
|
||||
public:
|
||||
virtual ~ICommonMountNameGenerator() { /* ... */ }
|
||||
virtual Result GenerateCommonMountName(char *name, size_t name_size) = 0;
|
||||
};
|
||||
|
||||
class IFileSystem;
|
||||
|
||||
Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs);
|
||||
Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs, std::unique_ptr<ICommonMountNameGenerator> &&generator);
|
||||
Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs, std::unique_ptr<ICommonMountNameGenerator> &&generator, bool use_data_cache, bool use_path_cache, bool multi_commit_supported);
|
||||
|
||||
void Unregister(const char *name);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace ams::fs::impl {
|
||||
|
||||
/* Delimiting of mount names. */
|
||||
constexpr inline const char ReservedMountNamePrefixCharacter = '@';
|
||||
constexpr inline const char * const MountNameDelimiter = ":/";
|
||||
|
||||
/* Filesystem names. */
|
||||
constexpr inline const char * const HostRootFileSystemMountName = "@Host";
|
||||
constexpr inline const char * const SdCardFileSystemMountName = "@Sdcard";
|
||||
constexpr inline const char * const GameCardFileSystemMountName = "@Gc";
|
||||
|
||||
constexpr inline size_t GameCardFileSystemMountNameSuffixLength = 1;
|
||||
|
||||
constexpr inline const char * const GameCardFileSystemMountNameUpdateSuffix = "U";
|
||||
constexpr inline const char * const GameCardFileSystemMountNameNormalSuffix = "N";
|
||||
constexpr inline const char * const GameCardFileSystemMountNameSecureSuffix = "S";
|
||||
|
||||
/* Built-in storage names. */
|
||||
constexpr inline const char * const BisCalibrationFilePartitionMountName = "@CalibFile";
|
||||
constexpr inline const char * const BisSafeModePartitionMountName = "@Safe";
|
||||
constexpr inline const char * const BisUserPartitionMountName = "@User";
|
||||
constexpr inline const char * const BisSystemPartitionMountName = "@System";
|
||||
|
||||
/* Content storage names. */
|
||||
constexpr inline const char * const ContentStorageSystemMountName = "@SystemContent";
|
||||
constexpr inline const char * const ContentStorageUserMountName = "@UserContent";
|
||||
constexpr inline const char * const ContentStorageSdCardMountName = "@SdCardContent";
|
||||
|
||||
|
||||
/* Registered update partition. */
|
||||
constexpr inline const char * const RegisteredUpdatePartitionMountName = "@RegUpdate";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere/fs/fs_common.hpp>
|
||||
|
||||
namespace ams::fs::impl {
|
||||
|
||||
Result QueryMountDataCacheSize(size_t *out, ncm::DataId data_id, ncm::StorageId storage_id);
|
||||
|
||||
Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id);
|
||||
Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size);
|
||||
Result MountData(const char *name, ncm::DataId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size, bool use_data_cache, bool use_path_cache);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::fs::impl {
|
||||
|
||||
enum FileSystemProxyType {
|
||||
FileSystemProxyType_Code = 0,
|
||||
FileSystemProxyType_Rom = 1,
|
||||
FileSystemProxyType_Logo = 2,
|
||||
FileSystemProxyType_Control = 3,
|
||||
FileSystemProxyType_Manual = 4,
|
||||
FileSystemProxyType_Meta = 5,
|
||||
FileSystemProxyType_Data = 6,
|
||||
FileSystemProxyType_Package = 7,
|
||||
FileSystemProxyType_UpdatePartition = 8,
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere/fs/fs_memory_management.hpp>
|
||||
|
||||
namespace ams::fs::impl {
|
||||
|
||||
class Newable {
|
||||
public:
|
||||
static void *operator new(size_t size) {
|
||||
return ::ams::fs::impl::Allocate(size);
|
||||
}
|
||||
|
||||
static void *operator new[](size_t size) {
|
||||
return ::ams::fs::impl::Allocate(size);
|
||||
}
|
||||
|
||||
static void operator delete(void *ptr, size_t size) {
|
||||
return ::ams::fs::impl::Deallocate(ptr, size);
|
||||
}
|
||||
|
||||
static void operator delete[](void *ptr, size_t size) {
|
||||
return ::ams::fs::impl::Deallocate(ptr, size);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user