mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-08 07:05:40 +12:00
[FS] Done with CreateFile
This commit is contained in:
parent
93d2d300b9
commit
49dcc25795
15 changed files with 85 additions and 3 deletions
|
@ -105,6 +105,12 @@ struct ArchiveSession {
|
||||||
// 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*>;
|
||||||
|
|
||||||
|
enum class CreateFileResult : u32 {
|
||||||
|
Success = 0,
|
||||||
|
AlreadyExists = 0x82044BE,
|
||||||
|
FileTooLarge = 0x86044D2
|
||||||
|
};
|
||||||
|
|
||||||
class ArchiveBase {
|
class ArchiveBase {
|
||||||
protected:
|
protected:
|
||||||
using Handle = u32;
|
using Handle = u32;
|
||||||
|
@ -161,6 +167,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
virtual std::string name() = 0;
|
virtual std::string name() = 0;
|
||||||
virtual u64 getFreeBytes() = 0;
|
virtual u64 getFreeBytes() = 0;
|
||||||
|
virtual CreateFileResult createFile(const FSPath& path, u64 size) = 0;
|
||||||
// Returns nullopt if opening the file failed, otherwise returns a file descriptor to it (nullptr if none is needed)
|
// Returns nullopt if opening the file failed, otherwise returns a file descriptor to it (nullptr if none is needed)
|
||||||
virtual FileDescriptor openFile(const FSPath& path, const FilePerms& perms) = 0;
|
virtual FileDescriptor openFile(const FSPath& path, const FilePerms& perms) = 0;
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ public:
|
||||||
std::string name() override { return "ExtSaveData"; }
|
std::string name() override { return "ExtSaveData"; }
|
||||||
|
|
||||||
ArchiveBase* openArchive(const FSPath& path) override;
|
ArchiveBase* openArchive(const FSPath& path) override;
|
||||||
|
CreateFileResult createFile(const FSPath& path, u64 size) 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;
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ public:
|
||||||
std::string name() override { return "SelfNCCH"; }
|
std::string name() override { return "SelfNCCH"; }
|
||||||
|
|
||||||
ArchiveBase* openArchive(const FSPath& path) override;
|
ArchiveBase* openArchive(const FSPath& path) override;
|
||||||
|
CreateFileResult createFile(const FSPath& path, u64 size) 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;
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ public:
|
||||||
std::string name() override { return "SaveData"; }
|
std::string name() override { return "SaveData"; }
|
||||||
|
|
||||||
ArchiveBase* openArchive(const FSPath& path) override;
|
ArchiveBase* openArchive(const FSPath& path) override;
|
||||||
|
CreateFileResult createFile(const FSPath& path, u64 size) 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;
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ public:
|
||||||
std::string name() override { return "SDMC"; }
|
std::string name() override { return "SDMC"; }
|
||||||
|
|
||||||
ArchiveBase* openArchive(const FSPath& path) override;
|
ArchiveBase* openArchive(const FSPath& path) override;
|
||||||
|
CreateFileResult createFile(const FSPath& path, u64 size) 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;
|
||||||
};
|
};
|
|
@ -62,6 +62,19 @@ public:
|
||||||
return read(data, count, sizeof(std::uint8_t));
|
return read(data, count, sizeof(std::uint8_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<bool, std::size_t> write(const void* data, std::size_t length, std::size_t dataSize) {
|
||||||
|
if (!isOpen()) {
|
||||||
|
return { false, std::numeric_limits<std::size_t>::max() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length == 0) return { true, 0 };
|
||||||
|
return { true, std::fwrite(data, dataSize, length, handle) };
|
||||||
|
}
|
||||||
|
|
||||||
|
auto writeBytes(const void* data, std::size_t count) {
|
||||||
|
return write(data, count, sizeof(std::uint8_t));
|
||||||
|
}
|
||||||
|
|
||||||
std::uint64_t size() {
|
std::uint64_t size() {
|
||||||
if (!isOpen()) return 0;
|
if (!isOpen()) return 0;
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,7 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Kernel(CPU& cpu, Memory& mem, GPU& gpu);
|
Kernel(CPU& cpu, Memory& mem, GPU& gpu);
|
||||||
|
void initializeFS() { return serviceManager.initializeFS(); }
|
||||||
void setVersion(u8 major, u8 minor);
|
void setVersion(u8 major, u8 minor);
|
||||||
void serviceSVC(u32 svc);
|
void serviceSVC(u32 svc);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
|
@ -53,4 +53,6 @@ public:
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
|
// Creates directories for NAND, ExtSaveData, etc if they don't already exist. Should be executed after loading a new ROM.
|
||||||
|
void initializeFilesystem();
|
||||||
};
|
};
|
|
@ -60,6 +60,7 @@ class ServiceManager {
|
||||||
public:
|
public:
|
||||||
ServiceManager(std::array<u32, 16>& regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel);
|
ServiceManager(std::array<u32, 16>& regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel);
|
||||||
void reset();
|
void reset();
|
||||||
|
void initializeFS() { fs.initializeFilesystem(); }
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
|
|
||||||
// Forward a SendSyncRequest IPC message to the service with the respective handle
|
// Forward a SendSyncRequest IPC message to the service with the respective handle
|
||||||
|
|
|
@ -3,6 +3,33 @@
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
CreateFileResult ExtSaveDataArchive::createFile(const FSPath& path, u64 size) {
|
||||||
|
if (size == 0)
|
||||||
|
Helpers::panic("ExtSaveData file does not support size == 0");
|
||||||
|
|
||||||
|
if (path.type == PathType::UTF16) {
|
||||||
|
if (!isPathSafe<PathType::UTF16>(path))
|
||||||
|
Helpers::panic("Unsafe path in ExtSaveData::CreateFile");
|
||||||
|
|
||||||
|
fs::path p = IOFile::getAppData() / "NAND";
|
||||||
|
p += fs::path(path.utf16_string).make_preferred();
|
||||||
|
|
||||||
|
if (fs::exists(p))
|
||||||
|
return CreateFileResult::AlreadyExists;
|
||||||
|
|
||||||
|
// Create a file of size "size" by creating an empty one, seeking to size - 1 and just writing a 0 there
|
||||||
|
IOFile file(p.string().c_str(), "wb");
|
||||||
|
if (file.seek(size - 1, SEEK_SET) && file.writeBytes("", 1).second == 1) {
|
||||||
|
return CreateFileResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateFileResult::FileTooLarge;
|
||||||
|
}
|
||||||
|
|
||||||
|
Helpers::panic("ExtSaveDataArchive::OpenFile: Failed");
|
||||||
|
return CreateFileResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
FileDescriptor ExtSaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) {
|
FileDescriptor ExtSaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) {
|
||||||
if (path.type == PathType::UTF16) {
|
if (path.type == PathType::UTF16) {
|
||||||
if (!isPathSafe<PathType::UTF16>(path))
|
if (!isPathSafe<PathType::UTF16>(path))
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
#include "fs/archive_ncch.hpp"
|
#include "fs/archive_ncch.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
CreateFileResult SelfNCCHArchive::createFile(const FSPath& path, u64 size) {
|
||||||
|
Helpers::panic("[SelfNCCH] CreateFile not yet supported");
|
||||||
|
return CreateFileResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
FileDescriptor SelfNCCHArchive::openFile(const FSPath& path, const FilePerms& perms) {
|
FileDescriptor SelfNCCHArchive::openFile(const FSPath& path, const FilePerms& perms) {
|
||||||
if (!hasRomFS()) {
|
if (!hasRomFS()) {
|
||||||
printf("Tried to open a SelfNCCH file without a RomFS\n");
|
printf("Tried to open a SelfNCCH file without a RomFS\n");
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
CreateFileResult SaveDataArchive::createFile(const FSPath& path, u64 size) {
|
||||||
|
Helpers::panic("[SaveData] CreateFile not yet supported");
|
||||||
|
return CreateFileResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
FileDescriptor SaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) {
|
FileDescriptor SaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) {
|
||||||
if (!cartHasSaveData()) {
|
if (!cartHasSaveData()) {
|
||||||
printf("Tried to read SaveData FS without save data\n");
|
printf("Tried to read SaveData FS without save data\n");
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
#include "fs/archive_sdmc.hpp"
|
#include "fs/archive_sdmc.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
CreateFileResult SDMCArchive::createFile(const FSPath& path, u64 size) {
|
||||||
|
Helpers::panic("[SDMC] CreateFile not yet supported");
|
||||||
|
return CreateFileResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
FileDescriptor SDMCArchive::openFile(const FSPath& path, const FilePerms& perms) {
|
FileDescriptor SDMCArchive::openFile(const FSPath& path, const FilePerms& perms) {
|
||||||
printf("SDMCArchive::OpenFile: Failed");
|
printf("SDMCArchive::OpenFile: Failed");
|
||||||
return FileError;
|
return FileError;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "services/fs.hpp"
|
#include "services/fs.hpp"
|
||||||
#include "kernel/kernel.hpp"
|
#include "kernel/kernel.hpp"
|
||||||
|
#include "io_file.hpp"
|
||||||
|
|
||||||
#ifdef CreateFile // windows.h defines this because of course it does.
|
#ifdef CreateFile // windows.h defines this because of course it does.
|
||||||
#undef CreateFile
|
#undef CreateFile
|
||||||
|
@ -32,6 +33,16 @@ void FSService::reset() {
|
||||||
priority = 0;
|
priority = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates directories for NAND, ExtSaveData, etc if they don't already exist. Should be executed after loading a new ROM.
|
||||||
|
void FSService::initializeFilesystem() {
|
||||||
|
const auto nandPath = IOFile::getAppData() / "NAND"; // Create NAND
|
||||||
|
// TODO: Savedata, SDMC, etc
|
||||||
|
|
||||||
|
if (!std::filesystem::is_directory(nandPath)) {
|
||||||
|
std::filesystem::create_directories(nandPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ArchiveBase* FSService::getArchiveFromID(u32 id) {
|
ArchiveBase* FSService::getArchiveFromID(u32 id) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case ArchiveID::SelfNCCH: return &selfNcch;
|
case ArchiveID::SelfNCCH: return &selfNcch;
|
||||||
|
@ -225,7 +236,7 @@ void FSService::createFile(u32 messagePointer) {
|
||||||
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);
|
||||||
const u64 bytesToZero = mem.read64(messagePointer + 28); // Bytes to fill with zeroes in the file
|
const u64 size = mem.read64(messagePointer + 28);
|
||||||
const u32 filePathPointer = mem.read32(messagePointer + 40);
|
const u32 filePathPointer = mem.read32(messagePointer + 40);
|
||||||
|
|
||||||
log("FS::CreateFile\n");
|
log("FS::CreateFile\n");
|
||||||
|
@ -240,8 +251,8 @@ void FSService::createFile(u32 messagePointer) {
|
||||||
ArchiveBase* archive = archiveObject->getData<ArchiveSession>()->archive;
|
ArchiveBase* archive = archiveObject->getData<ArchiveSession>()->archive;
|
||||||
auto filePath = readPath(filePathType, filePathPointer, filePathSize);
|
auto filePath = readPath(filePathType, filePathPointer, filePathSize);
|
||||||
|
|
||||||
for (auto c : filePath.utf16_string) std::cout << (char)c;
|
CreateFileResult res = archive->createFile(filePath, size);
|
||||||
Helpers::panic("Tried to create file");
|
mem.write32(messagePointer + 4, static_cast<u32>(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSService::getPriority(u32 messagePointer) {
|
void FSService::getPriority(u32 messagePointer) {
|
||||||
|
|
|
@ -49,6 +49,7 @@ void Emulator::runFrame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Emulator::loadROM(const std::filesystem::path& path) {
|
bool Emulator::loadROM(const std::filesystem::path& path) {
|
||||||
|
kernel.initializeFS();
|
||||||
auto extension = path.extension();
|
auto extension = path.extension();
|
||||||
|
|
||||||
if (extension == ".elf" || extension == ".axf")
|
if (extension == ".elf" || extension == ".axf")
|
||||||
|
|
Loading…
Add table
Reference in a new issue