mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
pf2: add volume init, context register/unregister
This commit is contained in:
parent
f9c5470ac9
commit
7b01d59b3b
19 changed files with 883 additions and 85 deletions
|
@ -25,3 +25,5 @@
|
|||
#include <vapours/prfile2/prfile2_system.hpp>
|
||||
#include <vapours/prfile2/pdm/prfile2_pdm_api.hpp>
|
||||
#include <vapours/prfile2/pdm/prfile2_pdm_disk_management.hpp>
|
||||
#include <vapours/prfile2/prfile2_fatfs.hpp>
|
||||
#include <vapours/prfile2/prfile2_volume.hpp>
|
||||
|
|
|
@ -25,4 +25,7 @@ namespace ams::prfile2::pdm {
|
|||
pdm::Error OpenDisk(InitDisk *init_disk_table, HandleType *out);
|
||||
pdm::Error CloseDisk(HandleType handle);
|
||||
|
||||
pdm::Error OpenPartition(HandleType disk_handle, u16 part_id, HandleType *out);
|
||||
pdm::Error ClosePartition(HandleType handle);
|
||||
|
||||
}
|
||||
|
|
|
@ -22,4 +22,6 @@ namespace ams::prfile2::pf {
|
|||
|
||||
int Initialize(u32 config, void *param);
|
||||
|
||||
int Attach(DriveTable **drive_table);
|
||||
|
||||
}
|
||||
|
|
|
@ -15,46 +15,59 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include <vapours/prfile2/prfile2_build_config.hpp>
|
||||
#include <vapours/prfile2/prfile2_handle.hpp>
|
||||
|
||||
namespace ams::prfile2::pf {
|
||||
|
||||
using DriveCharacter = char;
|
||||
|
||||
enum Error {
|
||||
Error_NoError = 0,
|
||||
Error_Ok = Error_NoError,
|
||||
Error_NoError = 0,
|
||||
Error_Ok = Error_NoError,
|
||||
|
||||
Error_EPERM = 1,
|
||||
Error_ENOENT = 2,
|
||||
Error_ESRCH = 3,
|
||||
Error_EIO = 5,
|
||||
Error_ENOEXEC = 8,
|
||||
Error_EBADF = 9,
|
||||
Error_ENOMEM = 12,
|
||||
Error_EACCES = 13,
|
||||
Error_EBUSY = 16,
|
||||
Error_EEXIST = 17,
|
||||
Error_ENODEV = 19,
|
||||
Error_EISDIR = 21,
|
||||
Error_EINVAL = 22,
|
||||
Error_ENFILE = 23,
|
||||
Error_EMFILE = 24,
|
||||
Error_EFBIG = 27,
|
||||
Error_ENOSPC = 28,
|
||||
Error_ENOLCK = 46,
|
||||
Error_ENOSYS = 88,
|
||||
Error_ENOTEMPTY = 90,
|
||||
Error_Generic = -1,
|
||||
|
||||
Error_EMOD_NOTREG = 100,
|
||||
Error_EMOD_NOTSPRT = 101,
|
||||
Error_EMOD_FCS = 102,
|
||||
Error_EMOD_SAFE = 103,
|
||||
|
||||
Error_ENOMEDIUM = 123,
|
||||
|
||||
Error_EEXFAT_NOTSPRT = 200,
|
||||
|
||||
Error_DFNC = 0x1000,
|
||||
|
||||
Error_SYSTEM = -1,
|
||||
Error_InvalidFileName = 1,
|
||||
Error_InvalidPathName = 2,
|
||||
Error_FileNotFound = 3,
|
||||
Error_TooManyVolumesAttached = 4,
|
||||
Error_DirectoryFull = 5,
|
||||
Error_VolumeFull = 6,
|
||||
Error_InvalidDiskFormat = 7,
|
||||
Error_FileAlreadyExists = 8,
|
||||
Error_VolumeNotMounted = 9,
|
||||
Error_InvalidParameter = 10,
|
||||
Error_WriteProtected = 11,
|
||||
Error_UnsupportedFormat = 12,
|
||||
Error_BrokenClusterChain = 13,
|
||||
Error_InvalidClusterNum = 14,
|
||||
Error_InvalidBpb = 15,
|
||||
Error_AccessOutOfVolume = 16,
|
||||
Error_DriverError = 17,
|
||||
Error_InvalidVolumeLabel = 18,
|
||||
Error_FileOpened = 19,
|
||||
Error_NotADirectory = 20,
|
||||
Error_TooManyFilesOpenedS = 21,
|
||||
Error_TooManyFilesOpenedU = 22,
|
||||
Error_NotAFile = 23,
|
||||
Error_ReadOnly = 24,
|
||||
Error_LockError = 25,
|
||||
Error_InternalError = 26,
|
||||
Error_EndOfFile = 27,
|
||||
Error_AccessNotAllowed = 28,
|
||||
Error_DirectoryNotEmpty = 29,
|
||||
Error_NotEnoughCachePages = 30,
|
||||
Error_DifferentDrive = 31,
|
||||
Error_DifferentEntry = 32,
|
||||
Error_InvalidEntry = 33,
|
||||
Error_InvalidSector = 34,
|
||||
Error_BrokenVolume = 35,
|
||||
Error_NotEffective = 36,
|
||||
Error_FileSizeOver = 37,
|
||||
Error_InvalidFileDiscriptor = 38,
|
||||
Error_InvalidLockFile = 39,
|
||||
Error_ExtensionNotRegistered = 40,
|
||||
Error_ExtensionError = 41,
|
||||
};
|
||||
|
||||
constexpr inline const int ReturnValueNoError = 0;
|
||||
|
@ -68,4 +81,44 @@ namespace ams::prfile2::pf {
|
|||
}
|
||||
}
|
||||
|
||||
struct CachePage {
|
||||
u16 status;
|
||||
u16 option;
|
||||
u8 *buffer_head;
|
||||
u8 *buffer_cur;
|
||||
u8 *buffer_dirty_start;
|
||||
u8 *buffer_dirty_end;
|
||||
u32 size;
|
||||
u32 sector;
|
||||
void *signature;
|
||||
CachePage *next;
|
||||
CachePage *prev;
|
||||
};
|
||||
static_assert(util::is_pod<CachePage>::value);
|
||||
|
||||
constexpr inline auto SectorBufferSize = 0x200;
|
||||
constexpr inline auto Log2SectorBufferSize = 9;
|
||||
static_assert((1u << Log2SectorBufferSize) == SectorBufferSize);
|
||||
|
||||
using SectorBuffer = u8[SectorBufferSize];
|
||||
static_assert(sizeof(SectorBuffer) == SectorBufferSize);
|
||||
|
||||
struct CacheSetting {
|
||||
CachePage *pages;
|
||||
SectorBuffer *buffers;
|
||||
u16 num_fat_pages;
|
||||
u16 num_data_pages;
|
||||
u32 fat_buf_size;
|
||||
u32 data_buf_size;
|
||||
};
|
||||
|
||||
struct DriveTable {
|
||||
CacheSetting *cache;
|
||||
HandleType partition_handle;
|
||||
DriveCharacter drive_char;
|
||||
u8 status;
|
||||
};
|
||||
|
||||
using TailBuf = u32;
|
||||
|
||||
}
|
||||
|
|
|
@ -25,53 +25,43 @@ namespace ams::prfile2 {
|
|||
constexpr inline const auto MaximumOpenDirectoryCountSystem = pf::MaximumDirectoryCount;
|
||||
constexpr inline const auto MaximumOpenDirectoryCountUser = pf::MaximumDirectoryCount;
|
||||
|
||||
enum InternalError {
|
||||
InternalError_NoError = 0,
|
||||
InternalError_Ok = InternalError_NoError,
|
||||
enum Error {
|
||||
Error_NoError = 0,
|
||||
Error_Ok = Error_NoError,
|
||||
|
||||
InternalError_Generic = -1,
|
||||
Error_EPERM = 1,
|
||||
Error_ENOENT = 2,
|
||||
Error_ESRCH = 3,
|
||||
Error_EIO = 5,
|
||||
Error_ENOEXEC = 8,
|
||||
Error_EBADF = 9,
|
||||
Error_ENOMEM = 12,
|
||||
Error_EACCES = 13,
|
||||
Error_EBUSY = 16,
|
||||
Error_EEXIST = 17,
|
||||
Error_ENODEV = 19,
|
||||
Error_EISDIR = 21,
|
||||
Error_EINVAL = 22,
|
||||
Error_ENFILE = 23,
|
||||
Error_EMFILE = 24,
|
||||
Error_EFBIG = 27,
|
||||
Error_ENOSPC = 28,
|
||||
Error_ENOLCK = 46,
|
||||
Error_ENOSYS = 88,
|
||||
Error_ENOTEMPTY = 90,
|
||||
|
||||
InternalError_InvalidFileName = 1,
|
||||
InternalError_InvalidPathName = 2,
|
||||
InternalError_FileNotFound = 3,
|
||||
InternalError_TooManyVolumesAttached = 4,
|
||||
InternalError_DirectoryFull = 5,
|
||||
InternalError_VolumeFull = 6,
|
||||
InternalError_InvalidDiskFormat = 7,
|
||||
InternalError_FileAlreadyExists = 8,
|
||||
InternalError_VolumeNotMounted = 9,
|
||||
InternalError_InvalidParameter = 10,
|
||||
InternalError_WriteProtected = 11,
|
||||
InternalError_UnsupportedFormat = 12,
|
||||
InternalError_BrokenClusterChain = 13,
|
||||
InternalError_InvalidClusterNum = 14,
|
||||
InternalError_InvalidBpb = 15,
|
||||
InternalError_AccessOutOfVolume = 16,
|
||||
InternalError_DriverError = 17,
|
||||
InternalError_InvalidVolumeLabel = 18,
|
||||
InternalError_FileOpened = 19,
|
||||
InternalError_NotADirectory = 20,
|
||||
InternalError_TooManyFilesOpenedS = 21,
|
||||
InternalError_TooManyFilesOpenedU = 22,
|
||||
InternalError_NotAFile = 23,
|
||||
InternalError_ReadOnly = 24,
|
||||
InternalError_LockError = 25,
|
||||
InternalError_InternalError = 26,
|
||||
InternalError_EndOfFile = 27,
|
||||
InternalError_AccessNotAllowed = 28,
|
||||
InternalError_DirectoryNotEmpty = 29,
|
||||
InternalError_NotEnoughCachePages = 30,
|
||||
InternalError_DifferentDrive = 31,
|
||||
InternalError_DifferentEntry = 32,
|
||||
InternalError_InvalidEntry = 33,
|
||||
InternalError_InvalidSector = 34,
|
||||
InternalError_BrokenVolume = 35,
|
||||
InternalError_NotEffective = 36,
|
||||
InternalError_FileSizeOver = 37,
|
||||
InternalError_InvalidFileDiscriptor = 38,
|
||||
InternalError_InvalidLockFile = 39,
|
||||
InternalError_ExtensionNotRegistered = 40,
|
||||
InternalError_ExtensionError = 41,
|
||||
Error_EMOD_NOTREG = 100,
|
||||
Error_EMOD_NOTSPRT = 101,
|
||||
Error_EMOD_FCS = 102,
|
||||
Error_EMOD_SAFE = 103,
|
||||
|
||||
Error_ENOMEDIUM = 123,
|
||||
|
||||
Error_EEXFAT_NOTSPRT = 200,
|
||||
|
||||
Error_DFNC = 0x1000,
|
||||
|
||||
Error_SYSTEM = -1,
|
||||
};
|
||||
|
||||
constexpr inline const u32 InvalidSector = std::numeric_limits<u32>::max();
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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/prfile2/prfile2_common.hpp>
|
||||
|
||||
namespace ams::prfile2 {
|
||||
|
||||
constexpr inline const auto LongNamePathCharacters = 260;
|
||||
|
||||
struct Volume;
|
||||
|
||||
struct DirectoryEntry {
|
||||
u16 long_name[LongNamePathCharacters];
|
||||
u32 attr;
|
||||
u64 file_size;
|
||||
u8 create_time_ms;
|
||||
u16 create_time;
|
||||
u16 create_date;
|
||||
u8 create_flags;
|
||||
u8 access_time_ms;
|
||||
u16 access_time;
|
||||
u16 access_date;
|
||||
u8 access_flags;
|
||||
u8 modify_time_ms;
|
||||
u16 modify_time;
|
||||
u16 modify_date;
|
||||
u8 modify_flags;
|
||||
Volume *volume;
|
||||
u32 path_len;
|
||||
u32 start_cluster;
|
||||
u32 entry_sector;
|
||||
u16 entry_offset;
|
||||
/* ... */
|
||||
u8 num_entry_lfns;
|
||||
u8 ordinal;
|
||||
u8 check_sum;
|
||||
char short_name[13];
|
||||
u8 small_letter_flag;
|
||||
/* ... */
|
||||
u16 full_path[LongNamePathCharacters];
|
||||
};
|
||||
|
||||
struct DirectoryTail {
|
||||
u32 tracker_size;
|
||||
pf::TailBuf tracker_buf[1];
|
||||
u32 *tracker_bits;
|
||||
};
|
||||
|
||||
}
|
64
libraries/libvapours/include/vapours/prfile2/prfile2_fat.hpp
Normal file
64
libraries/libvapours/include/vapours/prfile2/prfile2_fat.hpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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/prfile2/prfile2_common.hpp>
|
||||
|
||||
namespace ams::prfile2 {
|
||||
|
||||
struct FatHint {
|
||||
u32 chain_index;
|
||||
u32 cluster;
|
||||
};
|
||||
|
||||
using LastAccess = FatHint;
|
||||
|
||||
struct LastCluster {
|
||||
u32 num_last_cluster;
|
||||
u32 max_chain_index;
|
||||
};
|
||||
|
||||
struct ClusterLinkForVolume {
|
||||
u16 flag;
|
||||
u16 interval;
|
||||
u32 *buffer;
|
||||
u32 link_max;
|
||||
};
|
||||
|
||||
using ClusterBuf = u32;
|
||||
|
||||
struct ClusterLink {
|
||||
u64 position;
|
||||
ClusterBuf *buffer;
|
||||
u16 interval;
|
||||
u16 interval_offset;
|
||||
u32 save_index;
|
||||
u32 max_count;
|
||||
};
|
||||
|
||||
struct Volume;
|
||||
|
||||
struct FatFileDescriptor {
|
||||
u32 start_cluster;
|
||||
u32 *p_start_cluster;
|
||||
LastCluster last_cluster;
|
||||
LastAccess last_access;
|
||||
ClusterLink cluster_link;
|
||||
FatHint *hint;
|
||||
Volume *volume;
|
||||
/* ... */
|
||||
};
|
||||
|
||||
}
|
|
@ -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 <vapours/prfile2/prfile2_common.hpp>
|
||||
|
||||
namespace ams::prfile2::fatfs {
|
||||
|
||||
pf::Error Initialize(u32 config, void *param);
|
||||
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours/prfile2/prfile2_common.hpp>
|
||||
#include <vapours/prfile2/prfile2_build_config.hpp>
|
||||
|
||||
namespace ams::prfile2 {
|
||||
|
||||
|
|
|
@ -20,6 +20,6 @@ namespace ams::prfile2::system {
|
|||
|
||||
void Initialize();
|
||||
|
||||
pf::Error GetCurrentContextId(u64 *out);
|
||||
int GetCurrentContextId(u64 *out);
|
||||
|
||||
}
|
||||
|
|
196
libraries/libvapours/include/vapours/prfile2/prfile2_volume.hpp
Normal file
196
libraries/libvapours/include/vapours/prfile2/prfile2_volume.hpp
Normal file
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* 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/prfile2/prfile2_common.hpp>
|
||||
#include <vapours/prfile2/prfile2_critical_section.hpp>
|
||||
#include <vapours/prfile2/prfile2_entry.hpp>
|
||||
#include <vapours/prfile2/prfile2_fat.hpp>
|
||||
|
||||
namespace ams::prfile2 {
|
||||
|
||||
constexpr inline const auto MaxVolumes = 5;
|
||||
|
||||
struct Cursor {
|
||||
u64 position;
|
||||
u32 sector;
|
||||
u32 file_sector_index;
|
||||
u16 offset_in_sector;
|
||||
};
|
||||
|
||||
struct DirectoryCursor {
|
||||
u32 physical_entry_index;
|
||||
u32 logical_entry_index;
|
||||
u32 logical_seek_index;
|
||||
};
|
||||
|
||||
struct File;
|
||||
|
||||
struct FileLock {
|
||||
u16 mode;
|
||||
u16 count;
|
||||
u16 waiting_count;
|
||||
File *owner;
|
||||
u32 resource;
|
||||
};
|
||||
|
||||
struct SystemFileDescriptor {
|
||||
u32 status;
|
||||
FatFileDescriptor ffd;
|
||||
DirectoryEntry dir_entry;
|
||||
FileLock lock;
|
||||
u16 num_handlers;
|
||||
SystemFileDescriptor *next_sfd;
|
||||
};
|
||||
|
||||
struct SystemDirectoryDescriptor {
|
||||
u32 status;
|
||||
u16 num_handlers;
|
||||
FatFileDescriptor ffd;
|
||||
DirectoryEntry dir_entry;
|
||||
/* ... */
|
||||
u64 context_id;
|
||||
/* ... */
|
||||
};
|
||||
|
||||
struct File {
|
||||
u32 status;
|
||||
/* TODO OpenMode */ u32 open_mode;
|
||||
SystemFileDescriptor *sfd;
|
||||
FatHint hint;
|
||||
LastAccess last_access;
|
||||
pf::Error last_error;
|
||||
Cursor cursor;
|
||||
u16 lock_count;
|
||||
};
|
||||
|
||||
struct Directory {
|
||||
u32 stat;
|
||||
SystemDirectoryDescriptor *sdd;
|
||||
FatHint hint;
|
||||
DirectoryCursor cursor;
|
||||
/* ... */
|
||||
};
|
||||
|
||||
struct BiosParameterBlock {
|
||||
u16 bytes_per_sector;
|
||||
u32 num_reserved_sectors;
|
||||
u16 num_root_dir_entries;
|
||||
u32 sectors_per_cluster;
|
||||
u8 num_fats;
|
||||
u32 total_sectors;
|
||||
u32 sectors_per_fat;
|
||||
u32 root_dir_cluster;
|
||||
u16 fs_info_sector;
|
||||
u16 backup_boot_sector;
|
||||
u16 ext_flags;
|
||||
u16 ext_flags_;
|
||||
u8 media;
|
||||
FatFormat fat_fmt;
|
||||
u8 log2_bytes_per_sector;
|
||||
u8 log2_sectors_per_cluster;
|
||||
u8 num_active_fats;
|
||||
u8 num_active_fats_;
|
||||
u16 num_root_dir_sectors;
|
||||
u32 active_fat_sector;
|
||||
u32 active_fat_sector_;
|
||||
u32 first_root_dir_sector;
|
||||
u32 first_data_sector;
|
||||
u32 num_clusters;
|
||||
/* ... */
|
||||
};
|
||||
|
||||
using VolumeCallback = void (*)();
|
||||
|
||||
struct VolumeContext {
|
||||
u64 context_id;
|
||||
u32 volume_id;
|
||||
DirectoryEntry dir_entries[MaxVolumes];
|
||||
pf::Error last_error;
|
||||
pf::Error last_driver_error[MaxVolumes];
|
||||
pf::Error last_unk_error[MaxVolumes];
|
||||
/* ... */
|
||||
VolumeContext *next_used_context;
|
||||
union {
|
||||
VolumeContext *prev_used_context;
|
||||
VolumeContext *next_free_context;
|
||||
};
|
||||
};
|
||||
|
||||
struct Volume {
|
||||
BiosParameterBlock bpb;
|
||||
u32 num_free_clusters;
|
||||
u32 num_free_clusters_;
|
||||
u32 last_free_cluster;
|
||||
u32 last_free_cluster_;
|
||||
SystemFileDescriptor sfds[MaximumOpenFileCountSystem];
|
||||
File ufds[MaximumOpenFileCountUser];
|
||||
SystemDirectoryDescriptor sdds[MaximumOpenDirectoryCountSystem];
|
||||
Directory udds[MaximumOpenDirectoryCountUser];
|
||||
u32 num_open_files;
|
||||
u32 num_open_directories;
|
||||
/* ... */
|
||||
/* TODO: SectorCache cache; */
|
||||
VolumeContext *context;
|
||||
u64 context_id;
|
||||
DirectoryTail tail_entry;
|
||||
u32 volume_config;
|
||||
u32 file_config;
|
||||
u32 flags;
|
||||
pf::DriveCharacter drive_char;
|
||||
CriticalSection critical_section;
|
||||
u16 fsi_flag;
|
||||
ClusterLinkForVolume cluster_link;
|
||||
pf::Error last_error;
|
||||
pf::Error last_driver_error;
|
||||
/* ... */
|
||||
void *partition;
|
||||
VolumeCallback callback;
|
||||
const u8 *format_param;
|
||||
/* ... */
|
||||
/* TODO: ExtensionTable extension_table; */
|
||||
/* TODO: ExtensionData ext; */
|
||||
/* ... */
|
||||
};
|
||||
|
||||
struct VolumeSet {
|
||||
bool initialized;
|
||||
u32 num_attached_drives;
|
||||
u32 num_mounted_volumes;
|
||||
u32 config;
|
||||
void *param;
|
||||
/* TODO: CodeSet codeset; */
|
||||
u32 setting;
|
||||
CriticalSection critical_section;
|
||||
VolumeContext default_context;
|
||||
VolumeContext contexts[MaxVolumes];
|
||||
VolumeContext *used_context_head;
|
||||
VolumeContext *used_context_tail;
|
||||
VolumeContext *free_context_head;
|
||||
Volume volumes[MaxVolumes];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace ams::prfile2::vol {
|
||||
|
||||
pf::Error Initialize(u32 config, void *param);
|
||||
|
||||
pf::Error Attach(pf::DriveTable *drive_table);
|
||||
|
||||
VolumeContext *RegisterContext(u64 *out_context_id);
|
||||
pf::Error UnregisterContext();
|
||||
|
||||
}
|
|
@ -64,4 +64,27 @@ namespace ams::prfile2::pdm {
|
|||
return disk::CloseDisk(handle);
|
||||
}
|
||||
|
||||
pdm::Error OpenPartition(HandleType disk_handle, u16 part_id, HandleType *out) {
|
||||
/* Check the arguments. */
|
||||
if (out == nullptr || IsInvalidHandle(disk_handle)) {
|
||||
return pdm::Error_InvalidParameter;
|
||||
}
|
||||
|
||||
/* Set the output as invalid. */
|
||||
*out = InvalidHandle;
|
||||
|
||||
/* Open the partition. */
|
||||
return part::OpenPartition(disk_handle, part_id, out);
|
||||
}
|
||||
|
||||
pdm::Error ClosePartition(HandleType handle) {
|
||||
/* Check the input. */
|
||||
if (IsInvalidHandle(handle)) {
|
||||
return pdm::Error_InvalidParameter;
|
||||
}
|
||||
|
||||
/* Close the partition. */
|
||||
return part::ClosePartition(handle);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
62
libraries/libvapours/source/prfile2/pf/prfile2_pf_api.cpp
Normal file
62
libraries/libvapours/source/prfile2/pf/prfile2_pf_api.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
#include <stratosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
#include <mesosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
#include <exosphere.hpp>
|
||||
#else
|
||||
#include <vapours.hpp>
|
||||
#endif
|
||||
#include "prfile2_pf_errnum.hpp"
|
||||
|
||||
namespace ams::prfile2::pf {
|
||||
|
||||
|
||||
int Initialize(u32 config, void *param) {
|
||||
/* Initialize the fatfs api. */
|
||||
if (auto err = fatfs::Initialize(config, param)) {
|
||||
return ConvertReturnValue(err);
|
||||
}
|
||||
|
||||
/* Initialize the system api. */
|
||||
system::Initialize();
|
||||
return ConvertReturnValue(pf::Error_Ok);
|
||||
}
|
||||
|
||||
int Attach(DriveTable **drive_tables) {
|
||||
/* Check parameters. */
|
||||
if (drive_tables == nullptr || *drive_tables == nullptr) {
|
||||
return ConvertReturnValue(SetInternalErrorAndReturn(pf::Error_InvalidParameter));
|
||||
}
|
||||
|
||||
/* Attach each volume in the list. */
|
||||
for (auto *table = *drive_tables; table != nullptr; table = *(++drive_tables)) {
|
||||
if (auto err = vol::Attach(table); err != pf::Error_Ok) {
|
||||
/* Clear each unattached drive character. */
|
||||
for (table = *drive_tables; table != nullptr; table = *(++drive_tables)) {
|
||||
table->drive_char = 0;
|
||||
}
|
||||
return ConvertReturnValue(err);
|
||||
}
|
||||
}
|
||||
|
||||
return ConvertReturnValue(pf::Error_Ok);
|
||||
}
|
||||
|
||||
|
||||
}
|
28
libraries/libvapours/source/prfile2/pf/prfile2_pf_errnum.hpp
Normal file
28
libraries/libvapours/source/prfile2/pf/prfile2_pf_errnum.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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::prfile2::pf {
|
||||
|
||||
void SetInternalError(pf::Error err);
|
||||
|
||||
ALWAYS_INLINE pf::Error SetInternalErrorAndReturn(pf::Error err) {
|
||||
SetInternalError(err);
|
||||
return err;
|
||||
}
|
||||
|
||||
}
|
|
@ -34,7 +34,7 @@ namespace ams::prfile2 {
|
|||
|
||||
namespace {
|
||||
|
||||
constexpr inline const auto NumCriticalSectionResources = 5 /* TODO: NumVolumes */;
|
||||
constexpr inline const auto NumCriticalSectionResources = MaxVolumes + 1;
|
||||
|
||||
constinit os::SdkMutex g_crit_resource_mutex;
|
||||
constinit CriticalSection::Resource g_crit_resources[NumCriticalSectionResources];
|
||||
|
|
32
libraries/libvapours/source/prfile2/prfile2_fatfs.cpp
Normal file
32
libraries/libvapours/source/prfile2/prfile2_fatfs.cpp
Normal file
|
@ -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/>.
|
||||
*/
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
#include <stratosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
#include <mesosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
#include <exosphere.hpp>
|
||||
#else
|
||||
#include <vapours.hpp>
|
||||
#endif
|
||||
|
||||
namespace ams::prfile2::fatfs {
|
||||
|
||||
pf::Error Initialize(u32 config, void *param) {
|
||||
return vol::Initialize(config, param);
|
||||
}
|
||||
|
||||
}
|
|
@ -29,10 +29,10 @@ namespace ams::prfile2::system {
|
|||
/* ... */
|
||||
}
|
||||
|
||||
pf::Error GetCurrentContextId(u64 *out) {
|
||||
int GetCurrentContextId(u64 *out) {
|
||||
/* Check that out isn't null. */
|
||||
if (out == nullptr) {
|
||||
return static_cast<pf::Error>(-2);
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Set the output. */
|
||||
|
@ -42,7 +42,7 @@ namespace ams::prfile2::system {
|
|||
*out = 0;
|
||||
#endif
|
||||
|
||||
return pf::Error_Ok;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
227
libraries/libvapours/source/prfile2/prfile2_volume.cpp
Normal file
227
libraries/libvapours/source/prfile2/prfile2_volume.cpp
Normal file
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
#if defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||
#include <stratosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||
#include <mesosphere.hpp>
|
||||
#elif defined(ATMOSPHERE_IS_EXOSPHERE)
|
||||
#include <exosphere.hpp>
|
||||
#else
|
||||
#include <vapours.hpp>
|
||||
#endif
|
||||
#include "prfile2_volume_set.hpp"
|
||||
|
||||
namespace ams::prfile2::vol {
|
||||
|
||||
/* Global volume context object. */
|
||||
constinit VolumeContext g_vol_set;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline u32 CharacterCheckDisable = 0x10000;
|
||||
constexpr inline u32 CharacterCheckEnable = 0x20000;
|
||||
|
||||
constexpr inline u32 CharacterCheckMask = CharacterCheckDisable | CharacterCheckEnable;
|
||||
|
||||
constexpr inline u32 VolumeSetConfigMask = 0x5FFFFFFF;
|
||||
|
||||
VolumeContext *GetVolumeContextById(u64 context_id) {
|
||||
/* Get the volume set. */
|
||||
auto &vol_set = GetVolumeSet();
|
||||
|
||||
/* Acquire exclusive access to the volume set. */
|
||||
ScopedCriticalSection lk(vol_set.critical_section);
|
||||
|
||||
/* Find a matching context. */
|
||||
for (auto *ctx = vol_set.used_context_head; ctx != nullptr; ctx = ctx->next_used_context) {
|
||||
if (ctx->context_id == context_id) {
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pf::Error Initialize(u32 config, void *param) {
|
||||
/* Check the input config. */
|
||||
if ((config & ~CharacterCheckMask) != 0) {
|
||||
return pf::Error_InvalidParameter;
|
||||
}
|
||||
if ((config & CharacterCheckMask) == CharacterCheckMask) {
|
||||
return pf::Error_InvalidParameter;
|
||||
}
|
||||
|
||||
/* Get the volume set. */
|
||||
auto &vol_set = GetVolumeSet();
|
||||
|
||||
/* Clear the default volume context. */
|
||||
std::memset(std::addressof(vol_set.default_context), 0, sizeof(VolumeContext));
|
||||
vol_set.default_context.volume_id = 0;
|
||||
|
||||
/* Setup the context lists. */
|
||||
vol_set.used_context_head = nullptr;
|
||||
vol_set.used_context_tail = nullptr;
|
||||
vol_set.free_context_head = vol_set.contexts;
|
||||
for (auto i = 0; i < MaxVolumes - 1; ++i) {
|
||||
vol_set.contexts[i].next_free_context = std::addressof(vol_set.contexts[i + 1]);
|
||||
}
|
||||
vol_set.contexts[MaxVolumes - 1].next_free_context = nullptr;
|
||||
|
||||
/* Set the setting. */
|
||||
vol_set.setting = 1;
|
||||
|
||||
/* Set the config. */
|
||||
if ((config & CharacterCheckEnable) != 0) {
|
||||
vol_set.config |= CharacterCheckDisable;
|
||||
} else {
|
||||
vol_set.config &= ~CharacterCheckDisable;
|
||||
}
|
||||
vol_set.config &= VolumeSetConfigMask;
|
||||
|
||||
/* Clear number of attached drives/volumes. */
|
||||
vol_set.num_attached_drives = 0;
|
||||
vol_set.num_mounted_volumes = 0;
|
||||
|
||||
/* Set the parameter. */
|
||||
vol_set.param = param;
|
||||
|
||||
/* Set the codeset. */
|
||||
/* TODO */
|
||||
|
||||
/* Clear the volumes. */
|
||||
for (auto &volume : vol_set.volumes) {
|
||||
std::memset(std::addressof(volume), 0, sizeof(volume));
|
||||
}
|
||||
|
||||
/* Initialize the volume set critical section. */
|
||||
InitializeCriticalSection(std::addressof(vol_set.critical_section));
|
||||
|
||||
/* NOTE: Here "InitLockFile()" is called, but this doesn't seem used so far. TODO: Add if used? */
|
||||
|
||||
/* Mark initialized. */
|
||||
vol_set.initialized = true;
|
||||
|
||||
return pf::Error_Ok;
|
||||
}
|
||||
|
||||
pf::Error Attach(pf::DriveTable *drive_table) {
|
||||
AMS_UNUSED(drive_table);
|
||||
AMS_ABORT("vol::Attach");
|
||||
}
|
||||
|
||||
VolumeContext *RegisterContext(u64 *out_context_id) {
|
||||
/* Get the current context id. */
|
||||
u64 context_id = 0;
|
||||
system::GetCurrentContextId(std::addressof(context_id));
|
||||
if (out_context_id != nullptr) {
|
||||
*out_context_id = context_id;
|
||||
}
|
||||
|
||||
/* Get the volume set. */
|
||||
auto &vol_set = GetVolumeSet();
|
||||
|
||||
/* Acquire exclusive access to the volume set. */
|
||||
ScopedCriticalSection lk(vol_set.critical_section);
|
||||
|
||||
/* Get the volume context by ID. If we already have a context, return it. */
|
||||
if (VolumeContext *match = GetVolumeContextById(context_id); match != nullptr) {
|
||||
return match;
|
||||
}
|
||||
|
||||
/* Try to find a free context in the list. */
|
||||
VolumeContext *ctx = vol_set.free_context_head;
|
||||
if (ctx == nullptr) {
|
||||
vol_set.default_context.last_error = pf::Error_InternalError;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Update the free lists. */
|
||||
vol_set.free_context_head = ctx->next_free_context;
|
||||
if (VolumeContext *next = vol_set.used_context_head; next != nullptr) {
|
||||
next->prev_used_context = ctx;
|
||||
ctx->next_used_context = next;
|
||||
ctx->prev_used_context = nullptr;
|
||||
vol_set.used_context_head = ctx;
|
||||
} else {
|
||||
ctx->next_used_context = nullptr;
|
||||
ctx->prev_used_context = nullptr;
|
||||
vol_set.used_context_head = ctx;
|
||||
vol_set.used_context_tail = ctx;
|
||||
}
|
||||
|
||||
/* Set the context's fields. */
|
||||
ctx->context_id = context_id;
|
||||
ctx->last_error = pf::Error_Ok;
|
||||
for (auto i = 0; i < MaxVolumes; ++i) {
|
||||
ctx->last_driver_error[i] = pf::Error_Ok;
|
||||
ctx->last_unk_error[i] = pf::Error_Ok;
|
||||
}
|
||||
|
||||
/* Copy from the default context. */
|
||||
const auto volume_id = vol_set.default_context.volume_id;
|
||||
ctx->volume_id = volume_id;
|
||||
ctx->dir_entries[volume_id] = vol_set.default_context.dir_entries[volume_id];
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
pf::Error UnregisterContext() {
|
||||
/* Get the current context id. */
|
||||
u64 context_id = 0;
|
||||
system::GetCurrentContextId(std::addressof(context_id));
|
||||
|
||||
/* Get the volume set. */
|
||||
auto &vol_set = GetVolumeSet();
|
||||
|
||||
/* Acquire exclusive access to the volume set. */
|
||||
ScopedCriticalSection lk(vol_set.critical_section);
|
||||
|
||||
/* Get the volume context by ID. */
|
||||
VolumeContext *ctx = GetVolumeContextById(context_id);
|
||||
if (ctx == nullptr) {
|
||||
vol_set.default_context.last_error = pf::Error_InternalError;
|
||||
return pf::Error_InternalError;
|
||||
}
|
||||
|
||||
/* Update the lists. */
|
||||
auto *prev_used = ctx->prev_used_context;
|
||||
auto *next_used = ctx->next_used_context;
|
||||
if (prev_used != nullptr) {
|
||||
if (next_used != nullptr) {
|
||||
prev_used->next_used_context = next_used;
|
||||
next_used->prev_used_context = prev_used;
|
||||
} else {
|
||||
prev_used->next_used_context = nullptr;
|
||||
vol_set.used_context_tail = prev_used;
|
||||
}
|
||||
} else if (next_used != nullptr) {
|
||||
next_used->prev_used_context = nullptr;
|
||||
vol_set.used_context_head = next_used;
|
||||
} else {
|
||||
vol_set.used_context_head = nullptr;
|
||||
vol_set.used_context_tail = nullptr;
|
||||
}
|
||||
|
||||
ctx->next_used_context = nullptr;
|
||||
ctx->next_free_context = vol_set.free_context_head;
|
||||
vol_set.free_context_head = ctx;
|
||||
|
||||
return pf::Error_Ok;
|
||||
}
|
||||
|
||||
}
|
31
libraries/libvapours/source/prfile2/prfile2_volume_set.hpp
Normal file
31
libraries/libvapours/source/prfile2/prfile2_volume_set.hpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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::prfile2 {
|
||||
|
||||
namespace impl {
|
||||
|
||||
extern VolumeSet g_vol_set;
|
||||
|
||||
}
|
||||
|
||||
ALWAYS_INLINE VolumeSet &GetVolumeSet() {
|
||||
return impl::g_vol_set;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue