Compare commits
12 Commits
revision
...
experiment
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3107ec0127 | ||
|
|
60ea1dade2 | ||
|
|
a2f611edb7 | ||
|
|
8719e6da02 | ||
|
|
102e1e0e74 | ||
|
|
ceef76c428 | ||
|
|
7b01d59b3b | ||
|
|
f9c5470ac9 | ||
|
|
75f006b002 | ||
|
|
4466a74e40 | ||
|
|
dd6c9e1de1 | ||
|
|
7418c80e7f |
@@ -38,4 +38,5 @@
|
|||||||
#include <vapours/ams/ams_fatal_error_context.hpp>
|
#include <vapours/ams/ams_fatal_error_context.hpp>
|
||||||
|
|
||||||
#include <vapours/dd.hpp>
|
#include <vapours/dd.hpp>
|
||||||
#include <vapours/sdmmc.hpp>
|
#include <vapours/sdmmc.hpp>
|
||||||
|
#include <vapours/prfile2.hpp>
|
||||||
|
|||||||
31
libraries/libvapours/include/vapours/prfile2.hpp
Normal file
31
libraries/libvapours/include/vapours/prfile2.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/common.hpp>
|
||||||
|
#include <vapours/assert.hpp>
|
||||||
|
#include <vapours/results.hpp>
|
||||||
|
#include <vapours/util.hpp>
|
||||||
|
#include <vapours/svc.hpp>
|
||||||
|
|
||||||
|
#include <vapours/prfile2/prfile2_common.hpp>
|
||||||
|
#include <vapours/prfile2/prfile2_str.hpp>
|
||||||
|
#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/pdm/prfile2_pdm_upper_layer_api.hpp>
|
||||||
|
#include <vapours/prfile2/prfile2_fatfs.hpp>
|
||||||
|
#include <vapours/prfile2/prfile2_volume.hpp>
|
||||||
@@ -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/prfile2/pdm/prfile2_pdm_types.hpp>
|
||||||
|
#include <vapours/prfile2/pdm/prfile2_pdm_common.hpp>
|
||||||
|
#include <vapours/prfile2/pdm/prfile2_pdm_disk_management.hpp>
|
||||||
|
|
||||||
|
namespace ams::prfile2::pdm {
|
||||||
|
|
||||||
|
pdm::Error Initialize(u32 config, void *param);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* 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_build_config.hpp>
|
||||||
|
#include <vapours/prfile2/prfile2_handle.hpp>
|
||||||
|
#include <vapours/prfile2/pdm/prfile2_pdm_types.hpp>
|
||||||
|
|
||||||
|
namespace ams::prfile2::pdm {
|
||||||
|
|
||||||
|
constexpr inline const auto MaxDisks = 5;
|
||||||
|
constexpr inline const auto MaxPartitions = 5;
|
||||||
|
|
||||||
|
struct Disk;
|
||||||
|
struct Partition;
|
||||||
|
|
||||||
|
using PartitionEventCallback = void (*)(u32 event, void *param);
|
||||||
|
|
||||||
|
using EraseFunction = pdm::Error (*)(u32, u32);
|
||||||
|
|
||||||
|
struct DiskInfo {
|
||||||
|
u32 total_sectors;
|
||||||
|
u16 cylinders;
|
||||||
|
u8 heads;
|
||||||
|
u8 sectors_per_track;
|
||||||
|
u16 bytes_per_sector;
|
||||||
|
u32 media_attr;
|
||||||
|
void *format_param;
|
||||||
|
/* ... */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FunctionTable {
|
||||||
|
pdm::Error (*initialize)(HandleType disk_handle);
|
||||||
|
pdm::Error (*finalize)(HandleType disk_handle);
|
||||||
|
pdm::Error (*mount)(HandleType disk_handle);
|
||||||
|
pdm::Error (*unmount)(HandleType disk_handle);
|
||||||
|
pdm::Error (*format)(HandleType disk_handle, const u8 *);
|
||||||
|
pdm::Error (*physical_read)(HandleType disk_handle, u8 *dst, u32 block, u32 count, u32 *num_read);
|
||||||
|
pdm::Error (*physical_write)(HandleType disk_handle, const u8 *src, u32 block, u32 count, u32 *num_read);
|
||||||
|
pdm::Error (*get_disk_info)(HandleType disk_handle, DiskInfo *out);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DiskTable {
|
||||||
|
FunctionTable *function_table;
|
||||||
|
u64 ui_ext;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InitDisk {
|
||||||
|
pdm::Error (*function)(DiskTable *disk_table, u64 ui_ext);
|
||||||
|
u64 ui_ext;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ... */
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours/prfile2/prfile2_handle.hpp>
|
||||||
|
#include <vapours/prfile2/pdm/prfile2_pdm_common.hpp>
|
||||||
|
|
||||||
|
namespace ams::prfile2::pdm {
|
||||||
|
|
||||||
|
struct Disk {
|
||||||
|
u32 status;
|
||||||
|
DiskTable disk_table;
|
||||||
|
u32 signature;
|
||||||
|
u16 open_count;
|
||||||
|
u16 lock_count;
|
||||||
|
Disk *lock_handle;
|
||||||
|
DiskInfo disk_info;
|
||||||
|
InitDisk *init_disk_table;
|
||||||
|
HandleType current_partition_handle;
|
||||||
|
DiskCallback erase_callback;
|
||||||
|
bool is_inserted;
|
||||||
|
volatile NonBlockingProtocolType nbc;
|
||||||
|
volatile NonBlockingProtocolType nbc_detect;
|
||||||
|
volatile NonBlockingProtocolType nbc_req;
|
||||||
|
|
||||||
|
template<size_t Ix>
|
||||||
|
constexpr ALWAYS_INLINE bool GetStatusBit() const {
|
||||||
|
constexpr u32 Mask = (1u << Ix);
|
||||||
|
return (this->status & Mask) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t Ix>
|
||||||
|
constexpr ALWAYS_INLINE void SetStatusBit(bool en) {
|
||||||
|
constexpr u32 Mask = (1u << Ix);
|
||||||
|
if (en) {
|
||||||
|
this->status |= Mask;
|
||||||
|
} else {
|
||||||
|
this->status &= ~Mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool IsOpen() const { return this->GetStatusBit<0>(); }
|
||||||
|
constexpr void SetOpen(bool en) { this->SetStatusBit<0>(en); }
|
||||||
|
|
||||||
|
constexpr bool IsLocked() const { return this->GetStatusBit<1>(); }
|
||||||
|
constexpr void SetLocked(bool en) { this->SetStatusBit<1>(en); }
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace disk {
|
||||||
|
|
||||||
|
pdm::Error OpenDisk(InitDisk *init_disk_table, HandleType *out);
|
||||||
|
pdm::Error CloseDisk(HandleType handle);
|
||||||
|
|
||||||
|
/* ... */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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_handle.hpp>
|
||||||
|
#include <vapours/prfile2/pdm/prfile2_pdm_common.hpp>
|
||||||
|
#include <vapours/prfile2/pdm/prfile2_pdm_disk.hpp>
|
||||||
|
#include <vapours/prfile2/pdm/prfile2_pdm_partition.hpp>
|
||||||
|
|
||||||
|
namespace ams::prfile2::pdm {
|
||||||
|
|
||||||
|
struct PartitionHolder {
|
||||||
|
u32 signature;
|
||||||
|
Partition *partition;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DiskHolder {
|
||||||
|
u32 signature;
|
||||||
|
Disk *disk;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DiskSet {
|
||||||
|
u16 num_partitions;
|
||||||
|
u16 num_allocated_disks;
|
||||||
|
DiskHolder disk_holders[MaxDisks];
|
||||||
|
PartitionHolder partition_holders[MaxPartitions];
|
||||||
|
Disk disks[MaxDisks];
|
||||||
|
Partition partitions[MaxPartitions];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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 <vapours/prfile2/prfile2_handle.hpp>
|
||||||
|
#include <vapours/prfile2/pdm/prfile2_pdm_common.hpp>
|
||||||
|
|
||||||
|
namespace ams::prfile2::pdm {
|
||||||
|
|
||||||
|
struct Partition {
|
||||||
|
u32 status;
|
||||||
|
HandleType disk_handle;
|
||||||
|
u32 signature;
|
||||||
|
u16 partition_id;
|
||||||
|
u16 open_count;
|
||||||
|
Partition *lock_handle;
|
||||||
|
u32 start_sector;
|
||||||
|
u32 total_sector;
|
||||||
|
u32 mbr_sector;
|
||||||
|
u8 partition_type;
|
||||||
|
pdm::Error last_driver_error;
|
||||||
|
void *volume;
|
||||||
|
volatile NonBlockingProtocolType nbc_detect;
|
||||||
|
PartitionEventCallback event_callback;
|
||||||
|
void *event_callback_param;
|
||||||
|
|
||||||
|
template<size_t Ix>
|
||||||
|
constexpr ALWAYS_INLINE bool GetStatusBit() const {
|
||||||
|
constexpr u32 Mask = (1u << Ix);
|
||||||
|
return (this->status & Mask) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t Ix>
|
||||||
|
constexpr ALWAYS_INLINE void SetStatusBit(bool en) {
|
||||||
|
constexpr u32 Mask = (1u << Ix);
|
||||||
|
if (en) {
|
||||||
|
this->status |= Mask;
|
||||||
|
} else {
|
||||||
|
this->status &= ~Mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool IsOpen() const { return this->GetStatusBit<0>(); }
|
||||||
|
constexpr void SetOpen(bool en) { this->SetStatusBit<0>(en); }
|
||||||
|
|
||||||
|
constexpr bool IsLocked() const { return this->GetStatusBit<1>(); }
|
||||||
|
constexpr void SetLocked(bool en) { this->SetStatusBit<1>(en); }
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace part {
|
||||||
|
|
||||||
|
pdm::Error OpenPartition(HandleType disk_handle, u16 partition_id, HandleType *out);
|
||||||
|
pdm::Error ClosePartition(HandleType part_handle);
|
||||||
|
|
||||||
|
void SetDriverErrorCode(HandleType part_handle, pdm::Error err);
|
||||||
|
|
||||||
|
void CheckPartitionOpen(HandleType disk_handle, bool *out);
|
||||||
|
void NotifyMediaEvent(HandleType disk_handle, u32 event);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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_build_config.hpp>
|
||||||
|
#include <vapours/prfile2/prfile2_handle.hpp>
|
||||||
|
|
||||||
|
namespace ams::prfile2::pdm {
|
||||||
|
|
||||||
|
enum Error {
|
||||||
|
Error_NoError = 0,
|
||||||
|
Error_Ok = Error_NoError,
|
||||||
|
|
||||||
|
Error_InvalidParameter = 0x0001,
|
||||||
|
Error_InvalidMasterBoot = 0x0002,
|
||||||
|
Error_InvalidBootSector = 0x0003,
|
||||||
|
Error_InvalidBpb = 0x0004,
|
||||||
|
Error_NotExistMbr = 0x0005,
|
||||||
|
Error_NotExistEpbr = 0x0006,
|
||||||
|
Error_NotExistPartition = 0x0007,
|
||||||
|
Error_NotExistFreeDiskStruct = 0x0008,
|
||||||
|
Error_NotExistPartitionStruct = 0x0009,
|
||||||
|
Error_NotExistFreePartitionStruct = 0x000A,
|
||||||
|
Error_StateOpened = 0x000B,
|
||||||
|
Error_StateClosed = 0x000C,
|
||||||
|
Error_StateLocked = 0x000D,
|
||||||
|
Error_StateUnlocked = 0x000E,
|
||||||
|
Error_AccessPermission = 0x000F,
|
||||||
|
Error_WriteProtected = 0x0010,
|
||||||
|
Error_MediaEjected = 0x0011,
|
||||||
|
Error_OutOfRange = 0x0012,
|
||||||
|
Error_SystemCallError = 0x0013,
|
||||||
|
Error_LockError = 0x0014,
|
||||||
|
Error_DriverError = 0x0015,
|
||||||
|
Error_UnsupportDiskFormat = 0x0016,
|
||||||
|
};
|
||||||
|
|
||||||
|
using NonBlockingProtocolType = int;
|
||||||
|
|
||||||
|
using DiskCallback = void (*)();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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/pdm/prfile2_pdm_types.hpp>
|
||||||
|
#include <vapours/prfile2/pdm/prfile2_pdm_common.hpp>
|
||||||
|
#include <vapours/prfile2/pdm/prfile2_pdm_disk_management.hpp>
|
||||||
|
|
||||||
|
namespace ams::prfile2::pdm {
|
||||||
|
|
||||||
|
namespace part {
|
||||||
|
|
||||||
|
pdm::Error CheckDataEraseRequest(HandleType part_handle, bool *out);
|
||||||
|
pdm::Error CheckMediaDetect(HandleType part_handle, bool *out);
|
||||||
|
pdm::Error CheckMediaInsert(HandleType part_handle, bool *out);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace disk {
|
||||||
|
|
||||||
|
pdm::Error CheckDataEraseRequest(HandleType disk_handle, bool *out);
|
||||||
|
pdm::Error CheckMediaDetect(HandleType disk_handle, bool *out);
|
||||||
|
pdm::Error CheckMediaInsert(HandleType disk_handle, bool *out);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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 <vapours/prfile2/pf/prfile2_pf_config.hpp>
|
||||||
|
#include <vapours/prfile2/pf/prfile2_pf_types.hpp>
|
||||||
|
#include <vapours/prfile2/prfile2_critical_section.hpp>
|
||||||
|
|
||||||
|
namespace ams::prfile2::pf {
|
||||||
|
|
||||||
|
int Initialize(u32 config, void *param);
|
||||||
|
|
||||||
|
int Attach(DriveTable **drive_table);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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 <vapours/prfile2/prfile2_build_config.hpp>
|
||||||
|
|
||||||
|
namespace ams::prfile2::pf {
|
||||||
|
|
||||||
|
constexpr inline const auto MaximumFileCount = 256;
|
||||||
|
constexpr inline const auto MaximumDirectoryCount = 32;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* 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_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_Generic = -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;
|
||||||
|
constexpr inline const int ReturnValueError = -1;
|
||||||
|
|
||||||
|
constexpr inline int ConvertReturnValue(Error err) {
|
||||||
|
if (AMS_LIKELY(err == Error_NoError)) {
|
||||||
|
return ReturnValueNoError;
|
||||||
|
} else {
|
||||||
|
return ReturnValueError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
template<size_t Ix>
|
||||||
|
constexpr ALWAYS_INLINE bool GetStatusBit() const {
|
||||||
|
constexpr u32 Mask = (1u << Ix);
|
||||||
|
return (this->status & Mask) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t Ix>
|
||||||
|
constexpr ALWAYS_INLINE void SetStatusBit(bool en) {
|
||||||
|
constexpr u32 Mask = (1u << Ix);
|
||||||
|
if (en) {
|
||||||
|
this->status |= Mask;
|
||||||
|
} else {
|
||||||
|
this->status &= ~Mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool IsAttached() const { return this->GetStatusBit<0>(); }
|
||||||
|
constexpr void SetAttached(bool en) { this->SetStatusBit<0>(en); }
|
||||||
|
|
||||||
|
constexpr bool IsMounted() const { return this->GetStatusBit<1>(); }
|
||||||
|
constexpr void SetMounted(bool en) { this->SetStatusBit<1>(en); }
|
||||||
|
|
||||||
|
constexpr bool IsDiskInserted() const { return this->GetStatusBit<2>(); }
|
||||||
|
constexpr void SetDiskInserted(bool en) { this->SetStatusBit<2>(en); }
|
||||||
|
|
||||||
|
constexpr bool IsFlag12() const { return this->GetStatusBit<12>(); }
|
||||||
|
constexpr void SetFlag12(bool en) { this->SetStatusBit<12>(en); }
|
||||||
|
};
|
||||||
|
|
||||||
|
using TailBuf = u32;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* 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/common.hpp>
|
||||||
|
#include <vapours/assert.hpp>
|
||||||
|
#include <vapours/results.hpp>
|
||||||
|
#include <vapours/util.hpp>
|
||||||
|
#include <vapours/svc.hpp>
|
||||||
|
#include <vapours/dd.hpp>
|
||||||
|
|
||||||
|
#if defined(ATMOSPHERE_IS_EXOSPHERE) || defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||||
|
|
||||||
|
//#define AMS_PRFILE2_THREAD_SAFE
|
||||||
|
|
||||||
|
#elif defined(ATMOSPHERE_IS_MESOSPHERE)
|
||||||
|
|
||||||
|
//#define AMS_PRFILE2_THREAD_SAFE
|
||||||
|
|
||||||
|
#elif defined(ATMOSPHERE_IS_STRATOSPHERE)
|
||||||
|
|
||||||
|
#define AMS_PRFILE2_THREAD_SAFE
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Unknown execution context for ams::prfile2!"
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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 MinimumFatBufferSize = 1;
|
||||||
|
constexpr inline const auto MaximumFatBufferSize = (1 << 16) - 1;
|
||||||
|
constexpr inline const auto MinimumDataBufferSize = 1;
|
||||||
|
constexpr inline const auto MaximumDataBufferSize = (1 << 15) - 1;
|
||||||
|
|
||||||
|
constexpr inline const auto MinimumFatPages = 1;
|
||||||
|
constexpr inline const auto MinimumDataPages = 4;
|
||||||
|
|
||||||
|
struct SectorCache {
|
||||||
|
u32 mode;
|
||||||
|
u16 num_fat_pages;
|
||||||
|
u16 num_data_pages;
|
||||||
|
pf::CachePage *pages;
|
||||||
|
pf::CachePage *current_fat;
|
||||||
|
pf::CachePage *current_data;
|
||||||
|
pf::SectorBuffer *buffers;
|
||||||
|
u32 fat_buf_size;
|
||||||
|
u32 data_buf_size;
|
||||||
|
void *signature;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Volume;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ams::prfile2::cache {
|
||||||
|
|
||||||
|
void SetCache(Volume *vol, pf::CachePage *cache_page, pf::SectorBuffer *cache_buf, u16 num_fat_pages, u16 num_data_pages);
|
||||||
|
void SetFatBufferSize(Volume *vol, u32 size);
|
||||||
|
void SetDataBufferSize(Volume *vol, u32 size);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* 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_build_config.hpp>
|
||||||
|
#include <vapours/prfile2/pf/prfile2_pf_config.hpp>
|
||||||
|
#include <vapours/prfile2/pf/prfile2_pf_api_common.hpp>
|
||||||
|
#include <vapours/prfile2/prfile2_wide_string.hpp>
|
||||||
|
|
||||||
|
namespace ams::prfile2 {
|
||||||
|
|
||||||
|
constexpr inline const auto MaximumOpenFileCountSystem = pf::MaximumFileCount;
|
||||||
|
constexpr inline const auto MaximumOpenFileCountUser = pf::MaximumFileCount;
|
||||||
|
constexpr inline const auto MaximumOpenDirectoryCountSystem = pf::MaximumDirectoryCount;
|
||||||
|
constexpr inline const auto MaximumOpenDirectoryCountUser = pf::MaximumDirectoryCount;
|
||||||
|
|
||||||
|
enum Error {
|
||||||
|
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_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();
|
||||||
|
constexpr inline const u32 InvalidCluster = std::numeric_limits<u32>::max();
|
||||||
|
|
||||||
|
enum OpenMode {
|
||||||
|
OpenMode_None = 0,
|
||||||
|
OpenMode_Write = (1u << 0),
|
||||||
|
OpenMode_Read = (1u << 1),
|
||||||
|
OpenMode_Append = (1u << 2),
|
||||||
|
OpenMode_Plus = (1u << 3),
|
||||||
|
OpenMode_NoOverwrite = (1u << 4),
|
||||||
|
OpenMode_V = (1u << 5),
|
||||||
|
OpenMode_ContCluster = (1u << 6),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FatFormat {
|
||||||
|
FatFormat_Fat12 = 0,
|
||||||
|
FatFormat_Fat16 = 1,
|
||||||
|
FatFormat_Fat32 = 2,
|
||||||
|
FatFormat_ExFat = 3,
|
||||||
|
|
||||||
|
FatFormat_Invalid = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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 <vapours/prfile2/pf/prfile2_pf_config.hpp>
|
||||||
|
|
||||||
|
namespace ams::prfile2 {
|
||||||
|
|
||||||
|
struct CriticalSection {
|
||||||
|
enum State {
|
||||||
|
State_NotInitialized = 0,
|
||||||
|
State_Initialized = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Resource;
|
||||||
|
|
||||||
|
u8 state;
|
||||||
|
int lock_count;
|
||||||
|
Resource *resource;
|
||||||
|
u64 owner;
|
||||||
|
};
|
||||||
|
|
||||||
|
void InitializeCriticalSection(CriticalSection *cs);
|
||||||
|
void FinalizeCriticalSection(CriticalSection *cs);
|
||||||
|
|
||||||
|
void EnterCriticalSection(CriticalSection *cs);
|
||||||
|
void ExitCriticalSection(CriticalSection *cs);
|
||||||
|
|
||||||
|
class ScopedCriticalSection {
|
||||||
|
private:
|
||||||
|
CriticalSection *cs;
|
||||||
|
public:
|
||||||
|
ALWAYS_INLINE ScopedCriticalSection(CriticalSection *c) : cs(c) { EnterCriticalSection(this->cs); }
|
||||||
|
ALWAYS_INLINE ScopedCriticalSection(CriticalSection &c) : ScopedCriticalSection(std::addressof(c)) { /* ... */ }
|
||||||
|
|
||||||
|
ALWAYS_INLINE ~ScopedCriticalSection() { ExitCriticalSection(this->cs); }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
32
libraries/libvapours/include/vapours/prfile2/prfile2_drv.hpp
Normal file
32
libraries/libvapours/include/vapours/prfile2/prfile2_drv.hpp
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/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours/prfile2/prfile2_common.hpp>
|
||||||
|
|
||||||
|
namespace ams::prfile2 {
|
||||||
|
|
||||||
|
struct Volume;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ams::prfile2::drv {
|
||||||
|
|
||||||
|
pf::Error Initialize(Volume *volume);
|
||||||
|
|
||||||
|
bool IsDetected(Volume *volume);
|
||||||
|
bool IsInserted(Volume *volume);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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_build_config.hpp>
|
||||||
|
|
||||||
|
namespace ams::prfile2 {
|
||||||
|
|
||||||
|
using HandleType = util::BitPack32;
|
||||||
|
|
||||||
|
struct HandleField {
|
||||||
|
using Id = util::BitPack32::Field< 0, 8>;
|
||||||
|
using Kind = util::BitPack32::Field< 8, 8>;
|
||||||
|
using Signature = util::BitPack32::Field<16, 16>;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HandleKind {
|
||||||
|
HandleKind_Disk = 3,
|
||||||
|
HandleKind_Partition = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE HandleType ConstructHandle(u8 id, HandleKind kind, u16 signature) {
|
||||||
|
/* Construct the handle. */
|
||||||
|
HandleType val = {};
|
||||||
|
val.Set<HandleField::Id>(id);
|
||||||
|
val.Set<HandleField::Kind>(kind);
|
||||||
|
val.Set<HandleField::Signature>(signature);
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE u8 GetHandleId(HandleType handle) {
|
||||||
|
return handle.Get<HandleField::Id>();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE u16 GetHandleSignature(HandleType handle) {
|
||||||
|
return handle.Get<HandleField::Signature>();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline const HandleType InvalidHandle = {};
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE bool IsInvalidHandle(HandleType handle) {
|
||||||
|
return handle.value == 0;
|
||||||
|
}
|
||||||
|
static_assert(IsInvalidHandle(InvalidHandle));
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE HandleType ConstructDiskHandle(u8 id, u16 signature) { return ConstructHandle(id, HandleKind_Disk, signature); }
|
||||||
|
constexpr ALWAYS_INLINE HandleType ConstructPartitionHandle(u8 id, u16 signature) { return ConstructHandle(id, HandleKind_Partition, signature); }
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE bool IsDiskHandle(HandleType handle) { return handle.Get<HandleField::Kind>() == HandleKind_Disk; }
|
||||||
|
constexpr ALWAYS_INLINE bool IsPartitionHandle(HandleType handle) { return handle.Get<HandleField::Kind>() == HandleKind_Partition; }
|
||||||
|
|
||||||
|
}
|
||||||
65
libraries/libvapours/include/vapours/prfile2/prfile2_str.hpp
Normal file
65
libraries/libvapours/include/vapours/prfile2/prfile2_str.hpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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::str {
|
||||||
|
|
||||||
|
enum CodeMode {
|
||||||
|
CodeMode_Invalid = 0,
|
||||||
|
CodeMode_Local = 1,
|
||||||
|
CodeMode_Unicode = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TargetString {
|
||||||
|
TargetString_Head = 1,
|
||||||
|
TargetString_Tail = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct String {
|
||||||
|
const char *head;
|
||||||
|
const char *tail;
|
||||||
|
CodeMode code_mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
pf::Error Initialize(String *str, const char *s, CodeMode code_mode);
|
||||||
|
|
||||||
|
void SetCodeMode(String *str, CodeMode code_mode);
|
||||||
|
CodeMode GetCodeMode(const String *str);
|
||||||
|
|
||||||
|
char *GetPos(String *str, TargetString target);
|
||||||
|
void MovePos(String *str, s16 num_char);
|
||||||
|
|
||||||
|
u16 GetLength(String *str);
|
||||||
|
u16 GetNumChar(String *str, TargetString target);
|
||||||
|
|
||||||
|
int Compare(const String *str, const char *rhs);
|
||||||
|
int Compare(const String *str, const WideChar *rhs);
|
||||||
|
|
||||||
|
/* TODO: StrNCmp */
|
||||||
|
/* TODO: ToUpperNStr */
|
||||||
|
|
||||||
|
constexpr bool IsNull(const String *str) {
|
||||||
|
return str->head == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ams::prfile2 {
|
||||||
|
|
||||||
|
using String = str::String;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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::system {
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
|
|
||||||
|
int GetCurrentContextId(u64 *out);
|
||||||
|
|
||||||
|
}
|
||||||
238
libraries/libvapours/include/vapours/prfile2/prfile2_volume.hpp
Normal file
238
libraries/libvapours/include/vapours/prfile2/prfile2_volume.hpp
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
/*
|
||||||
|
* 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_cache.hpp>
|
||||||
|
#include <vapours/prfile2/prfile2_critical_section.hpp>
|
||||||
|
#include <vapours/prfile2/prfile2_drv.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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace pdm {
|
||||||
|
|
||||||
|
struct Partition;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
/* ... */
|
||||||
|
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;
|
||||||
|
/* ... */
|
||||||
|
HandleType partition_handle;
|
||||||
|
VolumeCallback callback;
|
||||||
|
const u8 *format_param;
|
||||||
|
/* ... */
|
||||||
|
/* TODO: ExtensionTable extension_table; */
|
||||||
|
/* TODO: ExtensionData ext; */
|
||||||
|
/* ... */
|
||||||
|
|
||||||
|
template<size_t Ix>
|
||||||
|
constexpr ALWAYS_INLINE bool GetFlagsBit() const {
|
||||||
|
constexpr u32 Mask = (1u << Ix);
|
||||||
|
return (this->flags & Mask) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t Ix>
|
||||||
|
constexpr ALWAYS_INLINE void SetFlagsBit(bool en) {
|
||||||
|
constexpr u32 Mask = (1u << Ix);
|
||||||
|
if (en) {
|
||||||
|
this->flags |= Mask;
|
||||||
|
} else {
|
||||||
|
this->flags &= ~Mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool IsAttached() const { return this->GetFlagsBit<0>(); }
|
||||||
|
constexpr void SetAttached(bool en) { this->SetFlagsBit<0>(en); }
|
||||||
|
|
||||||
|
constexpr bool IsMounted() const { return this->GetFlagsBit<1>(); }
|
||||||
|
constexpr void SetMounted(bool en) { this->SetFlagsBit<1>(en); }
|
||||||
|
|
||||||
|
constexpr bool IsFormatAfterMountRequested() const { return this->GetFlagsBit<4>(); }
|
||||||
|
constexpr void SetFormatAfterMountRequested(bool en) { this->SetFlagsBit<4>(en); }
|
||||||
|
|
||||||
|
constexpr bool IsNoFormattingByFatFsLayer() const { return this->GetFlagsBit<5>(); }
|
||||||
|
constexpr void SetNoFormattingByFatFsLayer(bool en) { this->SetFlagsBit<5>(en); }
|
||||||
|
|
||||||
|
constexpr bool IsDataEraseRequested() const { return this->GetFlagsBit<6>(); }
|
||||||
|
constexpr void SetDataEraseRequested(bool en) { this->SetFlagsBit<6>(en); }
|
||||||
|
|
||||||
|
constexpr bool IsFlag12() const { return this->GetFlagsBit<12>(); }
|
||||||
|
constexpr void SetFlag12(bool en) { this->SetFlagsBit<12>(en); }
|
||||||
|
};
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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/prfile2/prfile2_common.hpp>
|
||||||
|
|
||||||
|
namespace ams::prfile2 {
|
||||||
|
|
||||||
|
using WideChar = u16;
|
||||||
|
|
||||||
|
size_t w_strlen(const WideChar *s);
|
||||||
|
size_t w_strnlen(const WideChar *s, size_t length);
|
||||||
|
|
||||||
|
WideChar *w_strcpy(WideChar *dst, const WideChar *src);
|
||||||
|
WideChar *w_strncpy(WideChar *dst, const WideChar *src, size_t length);
|
||||||
|
|
||||||
|
int w_strcmp(const WideChar *lhs, const WideChar *rhs);
|
||||||
|
int w_strncmp(const WideChar *lhs, const WideChar *rhs, size_t length);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -75,6 +75,14 @@ namespace ams::util {
|
|||||||
this->value &= ~FieldMask;
|
this->value &= ~FieldMask;
|
||||||
this->value |= (static_cast<IntegralStorageType>(field_value) << FieldType::Index) & FieldMask;
|
this->value |= (static_cast<IntegralStorageType>(field_value) << FieldType::Index) & FieldMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE bool operator==(const BitPack &rhs) {
|
||||||
|
return this->value == rhs.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE bool operator!=(const BitPack &rhs) {
|
||||||
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
90
libraries/libvapours/source/prfile2/pdm/prfile2_pdm_api.cpp
Normal file
90
libraries/libvapours/source/prfile2/pdm/prfile2_pdm_api.cpp
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* 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_pdm_disk_set.hpp"
|
||||||
|
|
||||||
|
namespace ams::prfile2::pdm {
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
constinit DiskSet g_disk_set;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pdm::Error Initialize(u32 config, void *param) {
|
||||||
|
AMS_UNUSED(config, param);
|
||||||
|
|
||||||
|
/* Clear the disk set. */
|
||||||
|
std::memset(std::addressof(impl::g_disk_set), 0, sizeof(impl::g_disk_set));
|
||||||
|
|
||||||
|
return pdm::Error_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdm::Error OpenDisk(InitDisk *init_disk_table, HandleType *out) {
|
||||||
|
/* Check the arguments. */
|
||||||
|
if (out == nullptr) {
|
||||||
|
return pdm::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the output as invalid. */
|
||||||
|
*out = InvalidHandle;
|
||||||
|
|
||||||
|
/* Open the disk. */
|
||||||
|
return disk::OpenDisk(init_disk_table, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdm::Error CloseDisk(HandleType handle) {
|
||||||
|
/* Check the input. */
|
||||||
|
if (IsInvalidHandle(handle)) {
|
||||||
|
return pdm::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close the disk. */
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
148
libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk.cpp
Normal file
148
libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk.cpp
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* 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_pdm_disk_set.hpp"
|
||||||
|
|
||||||
|
namespace ams::prfile2::pdm::disk {
|
||||||
|
|
||||||
|
pdm::Error OpenDisk(InitDisk *init_disk_table, HandleType *out) {
|
||||||
|
/* Check the arguments. */
|
||||||
|
if (out == nullptr || init_disk_table == nullptr || init_disk_table->function == nullptr) {
|
||||||
|
return pdm::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find a free disk holder. */
|
||||||
|
DiskHolder *holder = nullptr;
|
||||||
|
for (auto &h : impl::g_disk_set.disk_holders) {
|
||||||
|
if (h.disk == nullptr) {
|
||||||
|
holder = std::addressof(h);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (holder == nullptr) {
|
||||||
|
return pdm::Error_NotExistFreeDiskStruct;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find a free disk. */
|
||||||
|
Disk *disk = nullptr;
|
||||||
|
for (auto &d : impl::g_disk_set.disks) {
|
||||||
|
if (!d.IsOpen()) {
|
||||||
|
disk = std::addressof(d);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (disk == nullptr) {
|
||||||
|
return pdm::Error_NotExistFreeDiskStruct;
|
||||||
|
}
|
||||||
|
const auto disk_id = disk - impl::g_disk_set.disks;
|
||||||
|
|
||||||
|
/* Call the disk initialze function. */
|
||||||
|
init_disk_table->function(std::addressof(disk->disk_table), init_disk_table->ui_ext);
|
||||||
|
|
||||||
|
/* Set the disk as open .*/
|
||||||
|
disk->SetOpen(true);
|
||||||
|
|
||||||
|
/* Set the init disk table. */
|
||||||
|
disk->init_disk_table = init_disk_table;
|
||||||
|
|
||||||
|
/* Note the opened disk. */
|
||||||
|
++impl::g_disk_set.num_allocated_disks;
|
||||||
|
|
||||||
|
/* Increment the disk's signature. */
|
||||||
|
disk->signature = static_cast<u16>(disk->signature + 1);
|
||||||
|
|
||||||
|
/* Increment the disk's open count. */
|
||||||
|
++disk->open_count;
|
||||||
|
|
||||||
|
/* Set the disk in the holder. */
|
||||||
|
holder->signature = disk->signature;
|
||||||
|
holder->disk = disk;
|
||||||
|
|
||||||
|
/* Set the output handle. */
|
||||||
|
*out = ConstructDiskHandle(disk_id, disk->signature);
|
||||||
|
|
||||||
|
/* If this was the first opening for the disk, initialize it. */
|
||||||
|
if (disk->open_count == 1) {
|
||||||
|
if (auto err = disk->disk_table.function_table->initialize(*out); err != pdm::Error_Ok) {
|
||||||
|
/* Close the disk. */
|
||||||
|
--disk->open_count;
|
||||||
|
disk->SetOpen(false);
|
||||||
|
--impl::g_disk_set.num_allocated_disks;
|
||||||
|
|
||||||
|
/* Reset the holder. */
|
||||||
|
holder->disk = nullptr;
|
||||||
|
|
||||||
|
return pdm::Error_DriverError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pdm::Error_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdm::Error CloseDisk(HandleType handle) {
|
||||||
|
/* Get the disk. */
|
||||||
|
Disk *disk = GetDisk(handle);
|
||||||
|
if (disk == nullptr) {
|
||||||
|
return pdm::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the disk is open and unlocked. */
|
||||||
|
if (!disk->IsOpen()) {
|
||||||
|
return pdm::Error_StateClosed;
|
||||||
|
}
|
||||||
|
if (disk->IsLocked()) {
|
||||||
|
return pdm::Error_StateLocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the disk holder. */
|
||||||
|
DiskHolder *holder = GetDiskHolder(handle);
|
||||||
|
if (holder == nullptr) {
|
||||||
|
return pdm::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close the disk. */
|
||||||
|
if (disk->open_count == 1) {
|
||||||
|
/* Finalize the disk. */
|
||||||
|
if (auto err = disk->disk_table.function_table->finalize(handle); err != pdm::Error_Ok) {
|
||||||
|
if (auto part = disk->current_partition_handle; part != InvalidHandle) {
|
||||||
|
part::SetDriverErrorCode(part, err);
|
||||||
|
}
|
||||||
|
return pdm::Error_DriverError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the disk as closed. */
|
||||||
|
disk->SetOpen(false);
|
||||||
|
--impl::g_disk_set.num_allocated_disks;
|
||||||
|
|
||||||
|
/* Clear the disk holder. */
|
||||||
|
holder->disk = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decrement the disk's open count. */
|
||||||
|
--disk->open_count;
|
||||||
|
|
||||||
|
return pdm::Error_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
103
libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk_set.hpp
Normal file
103
libraries/libvapours/source/prfile2/pdm/prfile2_pdm_disk_set.hpp
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* 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::pdm {
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
extern DiskSet g_disk_set;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE Disk *GetDisk(HandleType handle) {
|
||||||
|
if (AMS_LIKELY(IsDiskHandle(handle))) {
|
||||||
|
if (const auto id = GetHandleId(handle); AMS_LIKELY(id < MaxDisks)) {
|
||||||
|
const auto signature = GetHandleSignature(handle);
|
||||||
|
Disk *disk = std::addressof(impl::g_disk_set.disks[id]);
|
||||||
|
|
||||||
|
for (const auto &holder : impl::g_disk_set.disk_holders) {
|
||||||
|
if (holder.disk == disk && holder.signature == signature) {
|
||||||
|
return disk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE Disk *GetDiskUnsafe(HandleType handle) {
|
||||||
|
return std::addressof(impl::g_disk_set.disks[GetHandleId(handle)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE DiskHolder *GetDiskHolder(HandleType handle) {
|
||||||
|
if (AMS_LIKELY(IsDiskHandle(handle))) {
|
||||||
|
if (const auto id = GetHandleId(handle); AMS_LIKELY(id < MaxDisks)) {
|
||||||
|
const auto signature = GetHandleSignature(handle);
|
||||||
|
Disk *disk = std::addressof(impl::g_disk_set.disks[id]);
|
||||||
|
|
||||||
|
for (auto &holder : impl::g_disk_set.disk_holders) {
|
||||||
|
if (holder.disk == disk && holder.signature == signature) {
|
||||||
|
return std::addressof(holder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE Partition *GetPartition(HandleType handle) {
|
||||||
|
if (AMS_LIKELY(IsPartitionHandle(handle))) {
|
||||||
|
if (const auto id = GetHandleId(handle); AMS_LIKELY(id < MaxPartitions)) {
|
||||||
|
const auto signature = GetHandleSignature(handle);
|
||||||
|
Partition *part = std::addressof(impl::g_disk_set.partitions[id]);
|
||||||
|
|
||||||
|
for (const auto &holder : impl::g_disk_set.partition_holders) {
|
||||||
|
if (holder.partition == part && holder.signature == signature) {
|
||||||
|
return part;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE Partition *GetPartitionUnsafe(HandleType handle) {
|
||||||
|
return std::addressof(impl::g_disk_set.partitions[GetHandleId(handle)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE PartitionHolder *GetPartitionHolder(HandleType handle) {
|
||||||
|
if (AMS_LIKELY(IsPartitionHandle(handle))) {
|
||||||
|
if (const auto id = GetHandleId(handle); AMS_LIKELY(id < MaxPartitions)) {
|
||||||
|
const auto signature = GetHandleSignature(handle);
|
||||||
|
Partition *part = std::addressof(impl::g_disk_set.partitions[id]);
|
||||||
|
|
||||||
|
for (auto &holder : impl::g_disk_set.partition_holders) {
|
||||||
|
if (holder.partition == part && holder.signature == signature) {
|
||||||
|
return std::addressof(holder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* 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_pdm_disk_set.hpp"
|
||||||
|
|
||||||
|
namespace ams::prfile2::pdm::part {
|
||||||
|
|
||||||
|
pdm::Error OpenPartition(HandleType disk_handle, u16 partition_id, HandleType *out) {
|
||||||
|
/* Check the arguments. */
|
||||||
|
if (out == nullptr || disk_handle == InvalidHandle) {
|
||||||
|
return pdm::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find a free partition holder. */
|
||||||
|
PartitionHolder *holder = nullptr;
|
||||||
|
for (auto &h : impl::g_disk_set.partition_holders) {
|
||||||
|
if (h.partition == nullptr) {
|
||||||
|
holder = std::addressof(h);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (holder == nullptr) {
|
||||||
|
return pdm::Error_NotExistFreePartitionStruct;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Locate a free (or matching) partition. */
|
||||||
|
Partition *part = nullptr;
|
||||||
|
bool found_matching = false;
|
||||||
|
for (auto &p : impl::g_disk_set.partitions) {
|
||||||
|
if (p.IsOpen()) {
|
||||||
|
if (p.disk_handle == disk_handle && p.partition_id == partition_id) {
|
||||||
|
part = std::addressof(p);
|
||||||
|
found_matching = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (part == nullptr) {
|
||||||
|
part = std::addressof(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (part == nullptr) {
|
||||||
|
return pdm::Error_NotExistFreePartitionStruct;
|
||||||
|
}
|
||||||
|
const auto part_id = part - impl::g_disk_set.partitions;
|
||||||
|
|
||||||
|
/* If we're not working with a match, open the new partition. */
|
||||||
|
if (!found_matching) {
|
||||||
|
/* Set the partition as open. */
|
||||||
|
part->SetOpen(true);
|
||||||
|
|
||||||
|
/* Increment the number of open partitions. */
|
||||||
|
++impl::g_disk_set.num_partitions;
|
||||||
|
|
||||||
|
/* Set the partition's disk/id. */
|
||||||
|
part->disk_handle = disk_handle;
|
||||||
|
part->partition_id = partition_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increment the partition's signature. */
|
||||||
|
part->signature = static_cast<u16>(part->signature + 1);
|
||||||
|
|
||||||
|
/* Increment the partition's open count. */
|
||||||
|
++part->open_count;
|
||||||
|
|
||||||
|
/* Set the holder. */
|
||||||
|
holder->signature = part->signature;
|
||||||
|
holder->partition = part;
|
||||||
|
|
||||||
|
/* Set the output handle. */
|
||||||
|
*out = ConstructPartitionHandle(part_id, part->signature);
|
||||||
|
|
||||||
|
return pdm::Error_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdm::Error ClosePartition(HandleType part_handle) {
|
||||||
|
/* Get the partition. */
|
||||||
|
Partition *part = GetPartition(part_handle);
|
||||||
|
if (part == nullptr) {
|
||||||
|
return pdm::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the partition is open and unlocked. */
|
||||||
|
if (!part->IsOpen()) {
|
||||||
|
return pdm::Error_StateClosed;
|
||||||
|
}
|
||||||
|
if (part->IsLocked()) {
|
||||||
|
return pdm::Error_StateLocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the partition holder. */
|
||||||
|
PartitionHolder *holder = GetPartitionHolder(part_handle);
|
||||||
|
if (holder == nullptr) {
|
||||||
|
return pdm::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close the partition. */
|
||||||
|
if (part->open_count == 1) {
|
||||||
|
/* Set the partition as closed. */
|
||||||
|
part->SetOpen(false);
|
||||||
|
--impl::g_disk_set.num_partitions;
|
||||||
|
|
||||||
|
/* Clear the partition holder. */
|
||||||
|
holder->partition = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decrement the partition's open count. */
|
||||||
|
--part->open_count;
|
||||||
|
|
||||||
|
return pdm::Error_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDriverErrorCode(HandleType part_handle, pdm::Error err) {
|
||||||
|
GetPartitionUnsafe(part_handle)->last_driver_error = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckPartitionOpen(HandleType disk_handle, bool *out) {
|
||||||
|
/* TODO */
|
||||||
|
AMS_UNUSED(disk_handle, out);
|
||||||
|
AMS_ABORT("CheckPartitionOpen");
|
||||||
|
}
|
||||||
|
|
||||||
|
void NotifyMediaEvent(HandleType disk_handle, u32 event) {
|
||||||
|
/* TODO */
|
||||||
|
AMS_UNUSED(disk_handle, event);
|
||||||
|
AMS_ABORT("NotifyMediaEvent");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* 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_pdm_disk_set.hpp"
|
||||||
|
|
||||||
|
namespace ams::prfile2::pdm::disk {
|
||||||
|
|
||||||
|
pdm::Error CheckDataEraseRequest(HandleType disk_handle, bool *out) {
|
||||||
|
/* Check parameters. */
|
||||||
|
Disk *disk = GetDisk(disk_handle);
|
||||||
|
if (out == nullptr || disk == nullptr) {
|
||||||
|
return pdm::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for data erase function. */
|
||||||
|
*out = disk->erase_callback != nullptr;
|
||||||
|
return pdm::Error_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdm::Error CheckMediaDetect(HandleType disk_handle, bool *out) {
|
||||||
|
/* Check parameters. */
|
||||||
|
Disk *disk = GetDisk(disk_handle);
|
||||||
|
if (out == nullptr || disk == nullptr) {
|
||||||
|
return pdm::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default to no status change detected. */
|
||||||
|
*out = false;
|
||||||
|
|
||||||
|
/* Detect status change via disk nbc detect. */
|
||||||
|
volatile NonBlockingProtocolType nbc;
|
||||||
|
do {
|
||||||
|
do {
|
||||||
|
nbc = disk->nbc;
|
||||||
|
} while ((nbc & 1) != 0);
|
||||||
|
if (nbc != disk->nbc_detect) {
|
||||||
|
*out = true;
|
||||||
|
}
|
||||||
|
} while (nbc != disk->nbc);
|
||||||
|
|
||||||
|
return pdm::Error_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pdm::Error CheckMediaInsert(HandleType disk_handle, bool *out) {
|
||||||
|
/* Check parameters. */
|
||||||
|
Disk *disk = GetDisk(disk_handle);
|
||||||
|
if (out == nullptr || disk == nullptr) {
|
||||||
|
return pdm::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get whether the disk is inserted. */
|
||||||
|
*out = disk->is_inserted;
|
||||||
|
return pdm::Error_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* 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_pdm_disk_set.hpp"
|
||||||
|
|
||||||
|
namespace ams::prfile2::pdm::part {
|
||||||
|
|
||||||
|
pdm::Error CheckDataEraseRequest(HandleType part_handle, bool *out) {
|
||||||
|
/* Check parameters. */
|
||||||
|
Partition *part = GetPartition(part_handle);
|
||||||
|
if (out == nullptr || part == nullptr) {
|
||||||
|
return pdm::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the disk. */
|
||||||
|
return pdm::disk::CheckDataEraseRequest(part->disk_handle, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdm::Error CheckMediaDetect(HandleType part_handle, bool *out) {
|
||||||
|
/* Check parameters. */
|
||||||
|
Partition *part = GetPartition(part_handle);
|
||||||
|
if (out == nullptr || part == nullptr) {
|
||||||
|
return pdm::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the disk (unsafe/not checked). */
|
||||||
|
Disk *disk = GetDiskUnsafe(part->disk_handle);
|
||||||
|
|
||||||
|
/* Default to no status change detected. */
|
||||||
|
*out = false;
|
||||||
|
|
||||||
|
/* Detect status change via partition nbc detect. */
|
||||||
|
volatile NonBlockingProtocolType nbc;
|
||||||
|
do {
|
||||||
|
do {
|
||||||
|
nbc = disk->nbc;
|
||||||
|
} while ((nbc & 1) != 0);
|
||||||
|
if (nbc != part->nbc_detect) {
|
||||||
|
*out = true;
|
||||||
|
}
|
||||||
|
} while (nbc != disk->nbc);
|
||||||
|
|
||||||
|
return pdm::Error_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdm::Error CheckMediaInsert(HandleType part_handle, bool *out) {
|
||||||
|
/* Check parameters. */
|
||||||
|
Partition *part = GetPartition(part_handle);
|
||||||
|
if (out == nullptr || part == nullptr) {
|
||||||
|
return pdm::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the disk is inserted. */
|
||||||
|
return pdm::disk::CheckMediaInsert(part->disk_handle, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
49
libraries/libvapours/source/prfile2/prfile2_cache.cpp
Normal file
49
libraries/libvapours/source/prfile2/prfile2_cache.cpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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::cache {
|
||||||
|
|
||||||
|
void SetCache(Volume *vol, pf::CachePage *cache_page, pf::SectorBuffer *cache_buf, u16 num_fat_pages, u16 num_data_pages) {
|
||||||
|
/* Set the cache fields. */
|
||||||
|
vol->cache.pages = cache_page;
|
||||||
|
vol->cache.buffers = cache_buf;
|
||||||
|
vol->cache.num_fat_pages = num_fat_pages;
|
||||||
|
vol->cache.num_data_pages = num_data_pages;
|
||||||
|
std::memset(vol->cache.pages, 0, sizeof(*vol->cache.pages) * (num_fat_pages + num_data_pages));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetFatBufferSize(Volume *vol, u32 size) {
|
||||||
|
if (size > 0) {
|
||||||
|
vol->cache.fat_buf_size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDataBufferSize(Volume *vol, u32 size) {
|
||||||
|
if (size > 0) {
|
||||||
|
vol->cache.data_buf_size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
141
libraries/libvapours/source/prfile2/prfile2_critical_section.cpp
Normal file
141
libraries/libvapours/source/prfile2/prfile2_critical_section.cpp
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
|
||||||
|
#if defined(AMS_PRFILE2_THREAD_SAFE)
|
||||||
|
|
||||||
|
struct CriticalSection::Resource {
|
||||||
|
os::MutexType mutex;
|
||||||
|
bool in_use;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr inline const auto NumCriticalSectionResources = MaxVolumes + 1;
|
||||||
|
|
||||||
|
constinit os::SdkMutex g_crit_resource_mutex;
|
||||||
|
constinit CriticalSection::Resource g_crit_resources[NumCriticalSectionResources];
|
||||||
|
|
||||||
|
CriticalSection::Resource *AllocateCriticalSectionResource() {
|
||||||
|
std::scoped_lock lk(g_crit_resource_mutex);
|
||||||
|
|
||||||
|
for (auto &resource : g_crit_resources) {
|
||||||
|
if (!resource.in_use) {
|
||||||
|
resource.in_use = true;
|
||||||
|
return std::addressof(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AMS_ABORT("Failed to allocate critical section resource");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AcquireCriticalSectionResource(CriticalSection::Resource *resource) {
|
||||||
|
return os::LockMutex(std::addressof(resource->mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReleaseCriticalSectionResource(CriticalSection::Resource *resource) {
|
||||||
|
return os::UnlockMutex(std::addressof(resource->mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeCriticalSection(CriticalSection *cs) {
|
||||||
|
/* Check pre-condition. */
|
||||||
|
AMS_ASSERT(cs->state == CriticalSection::State_NotInitialized);
|
||||||
|
|
||||||
|
/* Perform initialization. */
|
||||||
|
if (cs->state == CriticalSection::State_NotInitialized) {
|
||||||
|
cs->resource = AllocateCriticalSectionResource();
|
||||||
|
cs->owner = 0;
|
||||||
|
cs->state = CriticalSection::State_Initialized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FinalizeCriticalSection(CriticalSection *cs) {
|
||||||
|
/* Check pre-condition. */
|
||||||
|
AMS_ASSERT(cs->state == CriticalSection::State_Initialized);
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
AMS_UNUSED(cs);
|
||||||
|
AMS_ABORT("prfile2::FinalizeCriticalSection");
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCriticalSection(CriticalSection *cs) {
|
||||||
|
/* Check pre-condition. */
|
||||||
|
AMS_ASSERT(cs->state == CriticalSection::State_Initialized);
|
||||||
|
|
||||||
|
if (AMS_LIKELY(cs->lock_count == 0)) {
|
||||||
|
/* Acquire the lock .*/
|
||||||
|
AcquireCriticalSectionResource(cs->resource);
|
||||||
|
system::GetCurrentContextId(std::addressof(cs->owner));
|
||||||
|
} else {
|
||||||
|
/* Get the current context id. */
|
||||||
|
u64 current_context_id;
|
||||||
|
system::GetCurrentContextId(std::addressof(current_context_id));
|
||||||
|
|
||||||
|
/* If the lock isn't already held, acquire it. */
|
||||||
|
if (cs->owner != current_context_id) {
|
||||||
|
AcquireCriticalSectionResource(cs->resource);
|
||||||
|
cs->owner = current_context_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increment the lock count. */
|
||||||
|
++cs->lock_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExitCriticalSection(CriticalSection *cs) {
|
||||||
|
/* Check pre-condition. */
|
||||||
|
AMS_ASSERT(cs->state == CriticalSection::State_Initialized);
|
||||||
|
|
||||||
|
/* Unlock. */
|
||||||
|
if ((--cs->lock_count) == 0) {
|
||||||
|
cs->owner = 0;
|
||||||
|
ReleaseCriticalSectionResource(cs->resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void InitializeCriticalSection(CriticalSection *cs) {
|
||||||
|
AMS_UNUSED(cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FinalizeCriticalSection(CriticalSection *cs) {
|
||||||
|
AMS_UNUSED(cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCriticalSection(CriticalSection *cs) {
|
||||||
|
AMS_UNUSED(cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExitCriticalSection(CriticalSection *cs) {
|
||||||
|
AMS_UNUSED(cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
61
libraries/libvapours/source/prfile2/prfile2_drv.cpp
Normal file
61
libraries/libvapours/source/prfile2/prfile2_drv.cpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* 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::drv {
|
||||||
|
|
||||||
|
pf::Error Initialize(Volume *volume) {
|
||||||
|
/* Check the volume. */
|
||||||
|
if (volume == nullptr) {
|
||||||
|
return pf::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the data erase request. */
|
||||||
|
bool data_erase;
|
||||||
|
if (auto pdm_err = pdm::part::CheckDataEraseRequest(volume->partition_handle, std::addressof(data_erase)); pdm_err != pdm::Error_Ok) {
|
||||||
|
return pf::Error_Generic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the data erase request flag. */
|
||||||
|
volume->SetDataEraseRequested(data_erase);
|
||||||
|
return pf::Error_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDetected(Volume *volume) {
|
||||||
|
/* Check detect status changed. */
|
||||||
|
/* NOTE: Error is not checked here. */
|
||||||
|
bool detected = false;
|
||||||
|
pdm::part::CheckMediaDetect(volume->partition_handle, std::addressof(detected));
|
||||||
|
return detected;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInserted(Volume *volume) {
|
||||||
|
/* Check inserted. */
|
||||||
|
/* NOTE: Error is not checked here. */
|
||||||
|
bool inserted = false;
|
||||||
|
pdm::part::CheckMediaInsert(volume->partition_handle, std::addressof(inserted));
|
||||||
|
return inserted;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
110
libraries/libvapours/source/prfile2/prfile2_str.cpp
Normal file
110
libraries/libvapours/source/prfile2/prfile2_str.cpp
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* 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::str {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/* TODO: Where does this come from? */
|
||||||
|
/* It's maximum path length * 2, but where should the definition live? */
|
||||||
|
constexpr inline size_t StringLengthMax = 520;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pf::Error Initialize(String *str, const char *s, CodeMode code_mode) {
|
||||||
|
/* Check parameters. */
|
||||||
|
if (str == nullptr || s == nullptr) {
|
||||||
|
return pf::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the string. */
|
||||||
|
switch (code_mode) {
|
||||||
|
case CodeMode_Local:
|
||||||
|
{
|
||||||
|
str->head = s;
|
||||||
|
str->tail = s + sizeof(char) * strnlen(s, StringLengthMax);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CodeMode_Unicode:
|
||||||
|
{
|
||||||
|
str->head = s;
|
||||||
|
str->tail = s + sizeof(WideChar) * w_strnlen(reinterpret_cast<const WideChar *>(s), StringLengthMax);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return pf::Error_InvalidParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the code mode. */
|
||||||
|
str->code_mode = code_mode;
|
||||||
|
|
||||||
|
return pf::Error_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCodeMode(String *str, CodeMode code_mode) {
|
||||||
|
str->code_mode = code_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeMode GetCodeMode(const String *str) {
|
||||||
|
return str->code_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *GetPos(String *str, TargetString target) {
|
||||||
|
if (target == TargetString_Head) {
|
||||||
|
return const_cast<char *>(str->head);
|
||||||
|
} else {
|
||||||
|
return const_cast<char *>(str->tail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MovePos(String *str, s16 num_char) {
|
||||||
|
AMS_UNUSED(str, num_char);
|
||||||
|
AMS_ABORT("TODO: oem charset");
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 GetLength(String *str) {
|
||||||
|
if (str->code_mode == CodeMode_Unicode) {
|
||||||
|
return (str->tail - str->head) / sizeof(WideChar);
|
||||||
|
} else {
|
||||||
|
return (str->tail - str->head) / sizeof(char);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 GetNumChar(String *str, TargetString target) {
|
||||||
|
AMS_UNUSED(str, target);
|
||||||
|
AMS_ABORT("TODO: oem charset");
|
||||||
|
}
|
||||||
|
|
||||||
|
int Compare(const String *str, const char *rhs) {
|
||||||
|
AMS_UNUSED(str, rhs);
|
||||||
|
AMS_ABORT("TODO: oem charset");
|
||||||
|
}
|
||||||
|
|
||||||
|
int Compare(const String *str, const WideChar *rhs) {
|
||||||
|
AMS_UNUSED(str, rhs);
|
||||||
|
AMS_ABORT("TODO: oem charset");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
48
libraries/libvapours/source/prfile2/prfile2_system.cpp
Normal file
48
libraries/libvapours/source/prfile2/prfile2_system.cpp
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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::system {
|
||||||
|
|
||||||
|
void Initialize() {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetCurrentContextId(u64 *out) {
|
||||||
|
/* Check that out isn't null. */
|
||||||
|
if (out == nullptr) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the output. */
|
||||||
|
#if defined(AMS_PRFILE2_THREAD_SAFE)
|
||||||
|
*out = reinterpret_cast<u64>(os::GetCurrentThread());
|
||||||
|
#else
|
||||||
|
*out = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
433
libraries/libvapours/source/prfile2/prfile2_volume.cpp
Normal file
433
libraries/libvapours/source/prfile2/prfile2_volume.cpp
Normal file
@@ -0,0 +1,433 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
VolumeContext *GetCurrentVolumeContext(u64 *out_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 current context id. */
|
||||||
|
u64 context_id = 0;
|
||||||
|
system::GetCurrentContextId(std::addressof(context_id));
|
||||||
|
if (out_context_id != nullptr) {
|
||||||
|
*out_context_id = context_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto *ctx = GetVolumeContextById(context_id); ctx != nullptr) {
|
||||||
|
return ctx;
|
||||||
|
} else {
|
||||||
|
return std::addressof(vol_set.default_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValidDriveCharacter(pf::DriveCharacter drive_char) {
|
||||||
|
return static_cast<u8>((drive_char & 0xDF) - 'A') < 26;
|
||||||
|
}
|
||||||
|
|
||||||
|
Volume *GetVolumeByDriveCharacter(pf::DriveCharacter drive_char) {
|
||||||
|
/* Get the volume set. */
|
||||||
|
auto &vol_set = GetVolumeSet();
|
||||||
|
|
||||||
|
/* Calculate the volume index. */
|
||||||
|
const auto index = std::toupper(static_cast<unsigned char>(drive_char)) - 'A';
|
||||||
|
|
||||||
|
/* Acquire exclusive access to the volume set. */
|
||||||
|
ScopedCriticalSection lk(vol_set.critical_section);
|
||||||
|
|
||||||
|
if (index < MaxVolumes) {
|
||||||
|
return std::addressof(vol_set.volumes[index]);
|
||||||
|
} else {
|
||||||
|
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) {
|
||||||
|
/* Get the volume set. */
|
||||||
|
auto &vol_set = GetVolumeSet();
|
||||||
|
|
||||||
|
/* Get the volume context for error tracking. */
|
||||||
|
u64 context_id = 0;
|
||||||
|
auto *vol_ctx = GetCurrentVolumeContext(std::addressof(context_id));
|
||||||
|
|
||||||
|
auto SetLastErrorAndReturn = [&] ALWAYS_INLINE_LAMBDA (pf::Error err) -> pf::Error { vol_ctx->last_error = err; return err; };
|
||||||
|
|
||||||
|
/* Check the drive table. */
|
||||||
|
if (drive_table == nullptr) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the drive table's character/status. */
|
||||||
|
const auto drive_char = drive_table->drive_char;
|
||||||
|
drive_table->drive_char = 0;
|
||||||
|
drive_table->status = 0;
|
||||||
|
|
||||||
|
/* Check that we can attach. */
|
||||||
|
if (vol_set.num_attached_drives >= MaxVolumes) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_TooManyVolumesAttached);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the cache setting. */
|
||||||
|
auto *cache_setting = drive_table->cache;
|
||||||
|
if (cache_setting == nullptr) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
|
||||||
|
}
|
||||||
|
if (cache_setting->fat_buf_size > MaximumFatBufferSize) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
|
||||||
|
}
|
||||||
|
if (cache_setting->data_buf_size > MaximumDataBufferSize) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
|
||||||
|
}
|
||||||
|
if (cache_setting->num_fat_pages < MinimumFatPages) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
|
||||||
|
}
|
||||||
|
if (cache_setting->num_data_pages < MinimumDataPages) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
|
||||||
|
}
|
||||||
|
if (cache_setting->pages == nullptr) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
|
||||||
|
}
|
||||||
|
if (cache_setting->buffers == nullptr) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
|
||||||
|
}
|
||||||
|
if (!util::IsAligned(reinterpret_cast<uintptr_t>(cache_setting->pages), alignof(u32))) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
|
||||||
|
}
|
||||||
|
if (!util::IsAligned(reinterpret_cast<uintptr_t>(cache_setting->buffers), alignof(u32))) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust the cache setting. */
|
||||||
|
cache_setting->fat_buf_size = std::max<u32>(cache_setting->fat_buf_size, MinimumFatBufferSize);
|
||||||
|
cache_setting->data_buf_size = std::max<u32>(cache_setting->data_buf_size, MinimumDataBufferSize);
|
||||||
|
|
||||||
|
/* Check the adjusted setting. */
|
||||||
|
if (cache_setting->fat_buf_size > cache_setting->num_fat_pages) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
|
||||||
|
}
|
||||||
|
if ((cache_setting->num_data_pages / cache_setting->data_buf_size) < MinimumDataPages) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate the drive character. */
|
||||||
|
if (drive_char != 0) {
|
||||||
|
if (!IsValidDriveCharacter(drive_char)) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_InvalidParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto *vol = GetVolumeByDriveCharacter(drive_char); vol == nullptr || vol->IsAttached()) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_InvalidVolumeLabel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the bulk of the attach. */
|
||||||
|
Volume *vol = nullptr;
|
||||||
|
{
|
||||||
|
/* Lock the volume set. */
|
||||||
|
ScopedCriticalSection lk(vol_set.critical_section);
|
||||||
|
|
||||||
|
/* Find a free volume. */
|
||||||
|
for (auto &v : vol_set.volumes) {
|
||||||
|
if (!v.IsAttached()) {
|
||||||
|
vol = std::addressof(v);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vol == nullptr) {
|
||||||
|
return SetLastErrorAndReturn(pf::Error_TooManyVolumesAttached);
|
||||||
|
}
|
||||||
|
const auto vol_id = vol - vol_set.volumes;
|
||||||
|
|
||||||
|
/* Clear the volume. */
|
||||||
|
std::memset(vol, 0, sizeof(*vol));
|
||||||
|
|
||||||
|
/* Initialize the volume. */
|
||||||
|
vol->num_free_clusters = InvalidCluster;
|
||||||
|
vol->num_free_clusters_ = InvalidCluster;
|
||||||
|
vol->last_free_cluster = InvalidCluster;
|
||||||
|
vol->partition_handle = drive_table->partition_handle;
|
||||||
|
InitializeCriticalSection(std::addressof(vol->critical_section));
|
||||||
|
vol->drive_char = 'A' + vol_id;
|
||||||
|
|
||||||
|
/* Setup directory tail. */
|
||||||
|
vol->tail_entry.tracker_size = util::size(vol->tail_entry.tracker_buf);
|
||||||
|
vol->tail_entry.tracker_bits = vol->tail_entry.tracker_buf;
|
||||||
|
|
||||||
|
/* NOTE: Cluster link is cleared here, but we already memset vol to zero, so it's unnecessary. */
|
||||||
|
|
||||||
|
/* Initialize driver for volume. */
|
||||||
|
if (auto err = drv::Initialize(vol); err != pf::Error_Ok) {
|
||||||
|
return SetLastErrorAndReturn(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup the cache. */
|
||||||
|
cache::SetCache(vol, drive_table->cache->pages, drive_table->cache->buffers, drive_table->cache->num_fat_pages, drive_table->cache->num_data_pages);
|
||||||
|
cache::SetFatBufferSize(vol, drive_table->cache->fat_buf_size);
|
||||||
|
cache::SetDataBufferSize(vol, drive_table->cache->data_buf_size);
|
||||||
|
|
||||||
|
/* Set flags. */
|
||||||
|
vol->SetAttached(true);
|
||||||
|
vol->SetFlag12(true);
|
||||||
|
|
||||||
|
/* Update the drive table. */
|
||||||
|
drive_table->SetAttached(true);
|
||||||
|
drive_table->drive_char = vol->drive_char;
|
||||||
|
|
||||||
|
/* Update the number of attached drives. */
|
||||||
|
if ((vol_set.num_attached_drives++) == 0) {
|
||||||
|
vol_set.default_context.volume_id = vol_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Acquire exclusive access to the volume set. */
|
||||||
|
ScopedCriticalSection lk(vol_set.critical_section);
|
||||||
|
|
||||||
|
/* Associate the volume to our context while we operate on it. */
|
||||||
|
vol->context = vol_ctx;
|
||||||
|
vol->context_id = context_id;
|
||||||
|
ON_SCOPE_EXIT { vol->context_id = 0; };
|
||||||
|
|
||||||
|
/* TODO: Copy volume root dir entry to all contexts. */
|
||||||
|
|
||||||
|
/* TODO: Clear tracking fields at the end of the volume. */
|
||||||
|
|
||||||
|
/* Perform mount as appropriate. */
|
||||||
|
const auto check_mount_err = /* TODO vol::CheckMediaInsertForAttachMount(vol) */ pf::Error_Ok;
|
||||||
|
const bool inserted = drv::IsInserted(vol);
|
||||||
|
if (check_mount_err != pf::Error_Ok) {
|
||||||
|
if (inserted) {
|
||||||
|
drive_table->SetDiskInserted(true);
|
||||||
|
}
|
||||||
|
vol_ctx->last_error = check_mount_err;
|
||||||
|
} else if (inserted) {
|
||||||
|
drive_table->SetDiskInserted(true);
|
||||||
|
if (auto mount_err = /* TODO vol::MountImpl(vol, 0x1B, false) */pf::Error_InternalError; mount_err != pf::Error_Ok) {
|
||||||
|
vol_ctx->last_error = mount_err;
|
||||||
|
} else {
|
||||||
|
drive_table->SetMounted(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pf::Error_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
109
libraries/libvapours/source/prfile2/prfile2_wide_string.cpp
Normal file
109
libraries/libvapours/source/prfile2/prfile2_wide_string.cpp
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
|
||||||
|
size_t w_strlen(const WideChar *s) {
|
||||||
|
const WideChar *cur;
|
||||||
|
for (cur = s; *cur != 0; ++cur) {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
return cur - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t w_strnlen(const WideChar *s, size_t length) {
|
||||||
|
const WideChar *cur;
|
||||||
|
for (cur = s; *cur != 0 && length != 0; ++cur, --length) {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
return cur - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
WideChar *w_strcpy(WideChar *dst, const WideChar *src) {
|
||||||
|
WideChar * const ret = dst;
|
||||||
|
while (true) {
|
||||||
|
const auto c = *(src++);
|
||||||
|
*(dst++) = c;
|
||||||
|
|
||||||
|
if (c == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
WideChar *w_strncpy(WideChar *dst, const WideChar *src, size_t length) {
|
||||||
|
WideChar * const ret = dst;
|
||||||
|
while (length > 1) {
|
||||||
|
const auto c = *(src++);
|
||||||
|
*(dst++) = c;
|
||||||
|
|
||||||
|
if (c == 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length == 1) {
|
||||||
|
*(dst++) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int w_strcmp(const WideChar *lhs, const WideChar *rhs) {
|
||||||
|
WideChar l, r;
|
||||||
|
while (true) {
|
||||||
|
l = *(lhs++);
|
||||||
|
r = *(rhs++);
|
||||||
|
if (l == 0 || r == 0 || l != r) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return l - r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int w_strncmp(const WideChar *lhs, const WideChar *rhs, size_t length) {
|
||||||
|
if (length == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WideChar l, r;
|
||||||
|
while (true) {
|
||||||
|
l = *(lhs++);
|
||||||
|
r = *(rhs++);
|
||||||
|
if (l == 0 || r == 0 || l != r) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((--length) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return l - r;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user