mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-08 23:25:40 +12:00
[FS] Implement OpenDirectory
This commit is contained in:
parent
1078253f6c
commit
494f3f1899
6 changed files with 89 additions and 5 deletions
|
@ -2,6 +2,7 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <filesystem>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
@ -111,6 +112,17 @@ struct ArchiveSession {
|
||||||
ArchiveSession(ArchiveBase* archive, const FSPath& filePath, bool isOpen = true) : archive(archive), path(filePath), isOpen(isOpen) {}
|
ArchiveSession(ArchiveBase* archive, const FSPath& filePath, bool isOpen = true) : archive(archive), path(filePath), isOpen(isOpen) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DirectorySession {
|
||||||
|
ArchiveBase* archive = nullptr;
|
||||||
|
// For directories which are mirrored to a specific path on the disk, this contains that path
|
||||||
|
// Otherwise this is a nullopt
|
||||||
|
std::optional<std::filesystem::path> pathOnDisk;
|
||||||
|
bool isOpen;
|
||||||
|
|
||||||
|
DirectorySession(ArchiveBase* archive, std::filesystem::path path, bool isOpen = true) : archive(archive), pathOnDisk(path),
|
||||||
|
isOpen(isOpen) {}
|
||||||
|
};
|
||||||
|
|
||||||
// Represents a file descriptor obtained from OpenFile. If the optional is nullopt, opening the file failed.
|
// Represents a file descriptor obtained from OpenFile. If the optional is nullopt, opening the file failed.
|
||||||
// Otherwise the fd of the opened file is returned (or nullptr if the opened file doesn't require one)
|
// Otherwise the fd of the opened file is returned (or nullptr if the opened file doesn't require one)
|
||||||
using FileDescriptor = std::optional<FILE*>;
|
using FileDescriptor = std::optional<FILE*>;
|
||||||
|
@ -201,6 +213,10 @@ public:
|
||||||
virtual FileDescriptor openFile(const FSPath& path, const FilePerms& perms) = 0;
|
virtual FileDescriptor openFile(const FSPath& path, const FilePerms& perms) = 0;
|
||||||
|
|
||||||
virtual ArchiveBase* openArchive(const FSPath& path) = 0;
|
virtual ArchiveBase* openArchive(const FSPath& path) = 0;
|
||||||
|
virtual std::optional<DirectorySession> openDirectory(const FSPath& path) {
|
||||||
|
Helpers::panic("Unimplemented OpenDirectory for %s archive", name().c_str());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
// Read size bytes from a file starting at offset "offset" into a certain buffer in memory
|
// Read size bytes from a file starting at offset "offset" into a certain buffer in memory
|
||||||
// Returns the number of bytes read, or nullopt if the read failed
|
// Returns the number of bytes read, or nullopt if the read failed
|
||||||
|
|
|
@ -13,6 +13,7 @@ public:
|
||||||
FormatInfo getFormatInfo(const FSPath& path) override;
|
FormatInfo getFormatInfo(const FSPath& path) override;
|
||||||
|
|
||||||
ArchiveBase* openArchive(const FSPath& path) override;
|
ArchiveBase* openArchive(const FSPath& path) override;
|
||||||
|
std::optional<DirectorySession> openDirectory(const FSPath& path) override;
|
||||||
FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override;
|
FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override;
|
||||||
std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override;
|
std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override;
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace SVCResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class KernelObjectType : u8 {
|
enum class KernelObjectType : u8 {
|
||||||
AddressArbiter, Archive, File, MemoryBlock, Process, ResourceLimit, Session, Dummy,
|
AddressArbiter, Archive, Directory, File, MemoryBlock, Process, ResourceLimit, Session, Dummy,
|
||||||
// Bundle waitable objects together in the enum to let the compiler optimize certain checks better
|
// Bundle waitable objects together in the enum to let the compiler optimize certain checks better
|
||||||
Event, Mutex, Port, Semaphore, Timer, Thread
|
Event, Mutex, Port, Semaphore, Timer, Thread
|
||||||
};
|
};
|
||||||
|
@ -144,6 +144,7 @@ static const char* kernelObjectTypeToString(KernelObjectType t) {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case KernelObjectType::AddressArbiter: return "address arbiter";
|
case KernelObjectType::AddressArbiter: return "address arbiter";
|
||||||
case KernelObjectType::Archive: return "archive";
|
case KernelObjectType::Archive: return "archive";
|
||||||
|
case KernelObjectType::Directory: return "directory";
|
||||||
case KernelObjectType::Event: return "event";
|
case KernelObjectType::Event: return "event";
|
||||||
case KernelObjectType::File: return "file";
|
case KernelObjectType::File: return "file";
|
||||||
case KernelObjectType::MemoryBlock: return "memory block";
|
case KernelObjectType::MemoryBlock: return "memory block";
|
||||||
|
|
|
@ -29,6 +29,7 @@ class FSService {
|
||||||
|
|
||||||
ArchiveBase* getArchiveFromID(u32 id);
|
ArchiveBase* getArchiveFromID(u32 id);
|
||||||
std::optional<Handle> openArchiveHandle(u32 archiveID, const FSPath& path);
|
std::optional<Handle> openArchiveHandle(u32 archiveID, const FSPath& path);
|
||||||
|
std::optional<Handle> openDirectoryHandle(ArchiveBase* archive, const FSPath& path);
|
||||||
std::optional<Handle> openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms);
|
std::optional<Handle> openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms);
|
||||||
FSPath readPath(u32 type, u32 pointer, u32 size);
|
FSPath readPath(u32 type, u32 pointer, u32 size);
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@ class FSService {
|
||||||
void initializeWithSdkVersion(u32 messagePointer);
|
void initializeWithSdkVersion(u32 messagePointer);
|
||||||
void isSdmcDetected(u32 messagePointer);
|
void isSdmcDetected(u32 messagePointer);
|
||||||
void openArchive(u32 messagePointer);
|
void openArchive(u32 messagePointer);
|
||||||
|
void openDirectory(u32 messagePointer);
|
||||||
void openFile(u32 messagePointer);
|
void openFile(u32 messagePointer);
|
||||||
void openFileDirectly(u32 messagePointer);
|
void openFileDirectly(u32 messagePointer);
|
||||||
void setPriority(u32 messagePointer);
|
void setPriority(u32 messagePointer);
|
||||||
|
|
|
@ -53,6 +53,29 @@ FileDescriptor SaveDataArchive::openFile(const FSPath& path, const FilePerms& pe
|
||||||
return FileError;
|
return FileError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<DirectorySession> SaveDataArchive::openDirectory(const FSPath& path) {
|
||||||
|
if (!cartHasSaveData()) {
|
||||||
|
printf("Tried to open SaveData directory without save data\n");
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.type == PathType::UTF16) {
|
||||||
|
if (!isPathSafe<PathType::UTF16>(path))
|
||||||
|
Helpers::panic("Unsafe path in SaveData::OpenDirectory");
|
||||||
|
|
||||||
|
fs::path p = IOFile::getAppData() / "SaveData";
|
||||||
|
p += fs::path(path.utf16_string).make_preferred();
|
||||||
|
|
||||||
|
if (fs::is_directory(p)) {
|
||||||
|
return DirectorySession(this, p);
|
||||||
|
} else {
|
||||||
|
Helpers::panic("Directory not found in SaveData::OpenDirectory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Helpers::panic("SaveDataArchive::OpenDirectory: Unimplemented path type");
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
ArchiveBase::FormatInfo SaveDataArchive::getFormatInfo(const FSPath& path) {
|
ArchiveBase::FormatInfo SaveDataArchive::getFormatInfo(const FSPath& path) {
|
||||||
Helpers::panic("Unimplemented SaveData::GetFormatInfo");
|
Helpers::panic("Unimplemented SaveData::GetFormatInfo");
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace FSCommands {
|
||||||
OpenFileDirectly = 0x08030204,
|
OpenFileDirectly = 0x08030204,
|
||||||
DeleteFile = 0x08040142,
|
DeleteFile = 0x08040142,
|
||||||
CreateFile = 0x08080202,
|
CreateFile = 0x08080202,
|
||||||
|
OpenDirectory = 0x080B0102,
|
||||||
OpenArchive = 0x080C00C2,
|
OpenArchive = 0x080C00C2,
|
||||||
CloseArchive = 0x080E0080,
|
CloseArchive = 0x080E0080,
|
||||||
IsSdmcDetected = 0x08170000,
|
IsSdmcDetected = 0x08170000,
|
||||||
|
@ -66,7 +67,7 @@ ArchiveBase* FSService::getArchiveFromID(u32 id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Handle> FSService::openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath,const FilePerms& perms) {
|
std::optional<Handle> FSService::openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms) {
|
||||||
FileDescriptor opened = archive->openFile(path, perms);
|
FileDescriptor opened = archive->openFile(path, perms);
|
||||||
if (opened.has_value()) { // If opened doesn't have a value, we failed to open the file
|
if (opened.has_value()) { // If opened doesn't have a value, we failed to open the file
|
||||||
auto handle = kernel.makeObject(KernelObjectType::File);
|
auto handle = kernel.makeObject(KernelObjectType::File);
|
||||||
|
@ -80,6 +81,19 @@ std::optional<Handle> FSService::openFileHandle(ArchiveBase* archive, const FSPa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<Handle> FSService::openDirectoryHandle(ArchiveBase* archive, const FSPath& path) {
|
||||||
|
std::optional<DirectorySession> opened = archive->openDirectory(path);
|
||||||
|
if (opened.has_value()) { // If opened doesn't have a value, we failed to open the directory
|
||||||
|
auto handle = kernel.makeObject(KernelObjectType::Directory);
|
||||||
|
auto& object = kernel.getObjects()[handle];
|
||||||
|
object.data = new DirectorySession(opened.value());
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
} else {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<Handle> FSService::openArchiveHandle(u32 archiveID, const FSPath& path) {
|
std::optional<Handle> FSService::openArchiveHandle(u32 archiveID, const FSPath& path) {
|
||||||
ArchiveBase* archive = getArchiveFromID(archiveID);
|
ArchiveBase* archive = getArchiveFromID(archiveID);
|
||||||
|
|
||||||
|
@ -123,8 +137,9 @@ void FSService::handleSyncRequest(u32 messagePointer) {
|
||||||
case FSCommands::InitializeWithSdkVersion: initializeWithSdkVersion(messagePointer); break;
|
case FSCommands::InitializeWithSdkVersion: initializeWithSdkVersion(messagePointer); break;
|
||||||
case FSCommands::IsSdmcDetected: isSdmcDetected(messagePointer); break;
|
case FSCommands::IsSdmcDetected: isSdmcDetected(messagePointer); break;
|
||||||
case FSCommands::OpenArchive: openArchive(messagePointer); break;
|
case FSCommands::OpenArchive: openArchive(messagePointer); break;
|
||||||
case FSCommands::OpenFile: openFile(messagePointer); break;
|
case FSCommands::OpenDirectory: openDirectory(messagePointer); break;
|
||||||
case FSCommands::OpenFileDirectly: openFileDirectly(messagePointer); break;
|
case FSCommands::OpenFile: [[likely]] openFile(messagePointer); break;
|
||||||
|
case FSCommands::OpenFileDirectly: [[likely]] openFileDirectly(messagePointer); break;
|
||||||
case FSCommands::SetPriority: setPriority(messagePointer); break;
|
case FSCommands::SetPriority: setPriority(messagePointer); break;
|
||||||
default: Helpers::panic("FS service requested. Command: %08X\n", command);
|
default: Helpers::panic("FS service requested. Command: %08X\n", command);
|
||||||
}
|
}
|
||||||
|
@ -210,6 +225,32 @@ void FSService::openFile(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FSService::openDirectory(u32 messagePointer) {
|
||||||
|
log("FS::OpenDirectory\n");
|
||||||
|
const Handle archiveHandle = (Handle)mem.read64(messagePointer + 4);
|
||||||
|
const u32 pathType = mem.read32(messagePointer + 12);
|
||||||
|
const u32 pathSize = mem.read32(messagePointer + 16);
|
||||||
|
const u32 pathPointer = mem.read32(messagePointer + 24);
|
||||||
|
|
||||||
|
KernelObject* archiveObject = kernel.getObject(archiveHandle, KernelObjectType::Archive);
|
||||||
|
if (archiveObject == nullptr) [[unlikely]] {
|
||||||
|
log("FS::OpenDirectory: Invalid archive handle %d\n", archiveHandle);
|
||||||
|
mem.write32(messagePointer + 4, Result::Failure);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveBase* archive = archiveObject->getData<ArchiveSession>()->archive;
|
||||||
|
const auto dirPath = readPath(pathType, pathPointer, pathSize);
|
||||||
|
std::optional<Handle> dir = openDirectoryHandle(archive, dirPath);
|
||||||
|
|
||||||
|
if (dir.has_value()) {
|
||||||
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
|
mem.write32(messagePointer + 12, dir.value());
|
||||||
|
} else {
|
||||||
|
Helpers::panic("FS::OpenDirectory failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FSService::openFileDirectly(u32 messagePointer) {
|
void FSService::openFileDirectly(u32 messagePointer) {
|
||||||
const u32 archiveID = mem.read32(messagePointer + 8);
|
const u32 archiveID = mem.read32(messagePointer + 8);
|
||||||
const u32 archivePathType = mem.read32(messagePointer + 12);
|
const u32 archivePathType = mem.read32(messagePointer + 12);
|
||||||
|
@ -247,7 +288,7 @@ void FSService::openFileDirectly(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSService::createFile(u32 messagePointer) {
|
void FSService::createFile(u32 messagePointer) {
|
||||||
const u32 archiveHandle = mem.read64(messagePointer + 8);
|
const Handle archiveHandle = mem.read64(messagePointer + 8);
|
||||||
const u32 filePathType = mem.read32(messagePointer + 16);
|
const u32 filePathType = mem.read32(messagePointer + 16);
|
||||||
const u32 filePathSize = mem.read32(messagePointer + 20);
|
const u32 filePathSize = mem.read32(messagePointer + 20);
|
||||||
const u32 attributes = mem.read32(messagePointer + 24);
|
const u32 attributes = mem.read32(messagePointer + 24);
|
||||||
|
|
Loading…
Add table
Reference in a new issue