Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moar filesystem #275

Merged
merged 2 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions include/fs/archive_system_save_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,18 @@ class SystemSaveDataArchive : public ArchiveBase {
SystemSaveDataArchive(Memory& mem) : ArchiveBase(mem) {}

u64 getFreeBytes() override {
Helpers::panic("Unimplemented GetFreeBytes for SystemSaveData archive");
Helpers::warn("Unimplemented GetFreeBytes for SystemSaveData archive");
return 32_MB;
}

std::string name() override { return "SystemSaveData"; }

//HorizonResult createDirectory(const FSPath& path) override;
HorizonResult createFile(const FSPath& path, u64 size) override;

HorizonResult deleteFile(const FSPath& path) override {
Helpers::panic("Unimplemented DeleteFile for SystemSaveData archive");
return Result::Success;
};
HorizonResult deleteFile(const FSPath& path) override;

Rust::Result<ArchiveBase*, HorizonResult> openArchive(const FSPath& path) override;
//Rust::Result<DirectorySession, HorizonResult> openDirectory(const FSPath& path) override;
Rust::Result<DirectorySession, HorizonResult> openDirectory(const FSPath& path) override;

FileDescriptor openFile(const FSPath& path, const FilePerms& perms) override;

Expand Down
1 change: 1 addition & 0 deletions include/services/boss.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class BOSSService {
void registerStorageEntry(u32 messagePointer);
void registerTask(u32 messagePointer);
void sendProperty(u32 messagePointer);
void setOptoutFlag(u32 messagePointer);
void startTask(u32 messagePointer);
void unregisterStorage(u32 messagePointer);
void unregisterTask(u32 messagePointer);
Expand Down
2 changes: 2 additions & 0 deletions include/services/fs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ class FSService {

// Service commands
void abnegateAccessRight(u32 messagePointer);
void cardSlotIsInserted(u32 messagePointer);
void createDirectory(u32 messagePointer);
void createExtSaveData(u32 messagePointer);
void createFile(u32 messagePointer);
void closeArchive(u32 messagePointer);
void controlArchive(u32 messagePointer);
void deleteDirectory(u32 messagePointer);
void deleteExtSaveData(u32 messagePointer);
void deleteFile(u32 messagePointer);
void formatSaveData(u32 messagePointer);
Expand Down
3 changes: 2 additions & 1 deletion src/core/fs/archive_save_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,9 @@ HorizonResult SaveDataArchive::createDirectory(const FSPath& path) {

HorizonResult SaveDataArchive::deleteFile(const FSPath& path) {
if (path.type == PathType::UTF16) {
if (!isPathSafe<PathType::UTF16>(path))
if (!isPathSafe<PathType::UTF16>(path)) {
Helpers::panic("Unsafe path in SaveData::DeleteFile");
}

fs::path p = IOFile::getAppData() / "SaveData";
p += fs::path(path.utf16_string).make_preferred();
Expand Down
32 changes: 31 additions & 1 deletion src/core/fs/archive_sdmc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,37 @@
namespace fs = std::filesystem;

HorizonResult SDMCArchive::createFile(const FSPath& path, u64 size) {
Helpers::panic("[SDMC] CreateFile not yet supported");
if (path.type == PathType::UTF16) {
if (!isPathSafe<PathType::UTF16>(path)) {
Helpers::panic("Unsafe path in SDMC::CreateFile");
}

fs::path p = IOFile::getAppData() / "SDMC";
p += fs::path(path.utf16_string).make_preferred();

if (fs::exists(p)) {
return Result::FS::AlreadyExists;
}

IOFile file(p.string().c_str(), "wb");

// If the size is 0, leave the file empty and return success
if (size == 0) {
file.close();
return Result::Success;
}

// If it is not empty, seek to size - 1 and write a 0 to create a file of size "size"
else if (file.seek(size - 1, SEEK_SET) && file.writeBytes("", 1).second == 1) {
file.close();
return Result::Success;
}

file.close();
return Result::FS::FileTooLarge;
}

Helpers::panic("SDMC::CreateFile: Failed");
return Result::Success;
}

Expand Down
59 changes: 59 additions & 0 deletions src/core/fs/archive_system_save_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,63 @@ HorizonResult SystemSaveDataArchive::createFile(const FSPath& path, u64 size) {

Helpers::panic("SystemSaveData::CreateFile: Failed");
return Result::Success;
}


HorizonResult SystemSaveDataArchive::deleteFile(const FSPath& path) {
if (path.type == PathType::UTF16) {
if (!isPathSafe<PathType::UTF16>(path)) {
Helpers::panic("Unsafe path in SystemSaveData::DeleteFile");
}

fs::path p = IOFile::getAppData() / ".." / "SharedFiles" / "SystemSaveData";
p += fs::path(path.utf16_string).make_preferred();

if (fs::is_directory(p)) {
Helpers::panic("SystemSaveData::DeleteFile: Tried to delete directory");
}

if (!fs::is_regular_file(p)) {
return Result::FS::FileNotFoundAlt;
}

std::error_code ec;
bool success = fs::remove(p, ec);

// It might still be possible for fs::remove to fail, if there's eg an open handle to a file being deleted
// In this case, print a warning, but still return success for now
if (!success) {
Helpers::warn("SystemSaveData::DeleteFile: fs::remove failed\n");
}

return Result::Success;
}

Helpers::panic("SystemSaveData::DeleteFile: Unknown path type");
return Result::Success;
}

Rust::Result<DirectorySession, HorizonResult> SystemSaveDataArchive::openDirectory(const FSPath& path) {
if (path.type == PathType::UTF16) {
if (!isPathSafe<PathType::UTF16>(path)) {
Helpers::panic("Unsafe path in SystemSaveData::OpenDirectory");
}

fs::path p = IOFile::getAppData() / ".." / "SharedFiles" / "SystemSaveData";
p += fs::path(path.utf16_string).make_preferred();

if (fs::is_regular_file(p)) {
printf("SystemSaveData: OpenDirectory used with a file path");
return Err(Result::FS::UnexpectedFileOrDir);
}

if (fs::is_directory(p)) {
return Ok(DirectorySession(this, p));
} else {
return Err(Result::FS::FileNotFoundAlt);
}
}

Helpers::panic("SystemSaveData::OpenDirectory: Unimplemented path type");
return Err(Result::Success);
}
11 changes: 11 additions & 0 deletions src/core/services/boss.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace BOSSCommands {
UnregisterStorage = 0x00030000,
GetTaskStorageInfo = 0x00040000,
RegisterNewArrivalEvent = 0x00080002,
SetOptoutFlag = 0x00090040,
GetOptoutFlag = 0x000A0000,
RegisterTask = 0x000B00C2,
UnregisterTask = 0x000C0082,
Expand Down Expand Up @@ -53,6 +54,7 @@ void BOSSService::handleSyncRequest(u32 messagePointer) {
case BOSSCommands::RegisterStorageEntry: registerStorageEntry(messagePointer); break;
case BOSSCommands::RegisterTask: registerTask(messagePointer); break;
case BOSSCommands::SendProperty: sendProperty(messagePointer); break;
case BOSSCommands::SetOptoutFlag: setOptoutFlag(messagePointer); break;
case BOSSCommands::StartTask: startTask(messagePointer); break;
case BOSSCommands::UnregisterStorage: unregisterStorage(messagePointer); break;
case BOSSCommands::UnregisterTask: unregisterTask(messagePointer); break;
Expand All @@ -66,6 +68,15 @@ void BOSSService::initializeSession(u32 messagePointer) {
mem.write32(messagePointer + 4, Result::Success);
}

void BOSSService::setOptoutFlag(u32 messagePointer) {
const s8 flag = static_cast<s8>(mem.read8(messagePointer + 4));
log("BOSS::SetOptoutFlag (flag = %d)\n", flag);
optoutFlag = flag;

mem.write32(messagePointer, IPC::responseHeader(0x9, 1, 0));
mem.write32(messagePointer + 4, Result::Success);
}

void BOSSService::getOptoutFlag(u32 messagePointer) {
log("BOSS::GetOptoutFlag\n");
mem.write32(messagePointer, IPC::responseHeader(0xA, 2, 0));
Expand Down
26 changes: 26 additions & 0 deletions src/core/services/fs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace FSCommands {
OpenFile = 0x080201C2,
OpenFileDirectly = 0x08030204,
DeleteFile = 0x08040142,
DeleteDirectory = 0x08060142,
DeleteDirectoryRecursively = 0x08070142,
CreateFile = 0x08080202,
CreateDirectory = 0x08090182,
OpenDirectory = 0x080B0102,
Expand All @@ -26,6 +28,7 @@ namespace FSCommands {
GetFreeBytes = 0x08120080,
IsSdmcDetected = 0x08170000,
IsSdmcWritable = 0x08180000,
CardSlotIsInserted = 0x08210000,
AbnegateAccessRight = 0x08400040,
GetFormatInfo = 0x084500C2,
GetArchiveResource = 0x08490040,
Expand Down Expand Up @@ -160,11 +163,13 @@ FSPath FSService::readPath(u32 type, u32 pointer, u32 size) {
void FSService::handleSyncRequest(u32 messagePointer) {
const u32 command = mem.read32(messagePointer);
switch (command) {
case FSCommands::CardSlotIsInserted: cardSlotIsInserted(messagePointer); break;
case FSCommands::CreateDirectory: createDirectory(messagePointer); break;
case FSCommands::CreateExtSaveData: createExtSaveData(messagePointer); break;
case FSCommands::CreateFile: createFile(messagePointer); break;
case FSCommands::ControlArchive: controlArchive(messagePointer); break;
case FSCommands::CloseArchive: closeArchive(messagePointer); break;
case FSCommands::DeleteDirectory: deleteDirectory(messagePointer); break;
case FSCommands::DeleteExtSaveData: deleteExtSaveData(messagePointer); break;
case FSCommands::DeleteFile: deleteFile(messagePointer); break;
case FSCommands::FormatSaveData: formatSaveData(messagePointer); break;
Expand Down Expand Up @@ -414,6 +419,18 @@ void FSService::deleteFile(u32 messagePointer) {
mem.write32(messagePointer + 4, static_cast<u32>(res));
}

void FSService::deleteDirectory(u32 messagePointer) {
const Handle archiveHandle = Handle(mem.read64(messagePointer + 8));
const u32 filePathType = mem.read32(messagePointer + 16);
const u32 filePathSize = mem.read32(messagePointer + 20);
const u32 filePathPointer = mem.read32(messagePointer + 28);
log("FS::DeleteDirectory\n");

Helpers::warn("Stubbed FS::DeleteDirectory call!");
mem.write32(messagePointer, IPC::responseHeader(0x806, 1, 0));
mem.write32(messagePointer + 4, Result::Success);
}

void FSService::getFormatInfo(u32 messagePointer) {
const u32 archiveID = mem.read32(messagePointer + 4);
const u32 pathType = mem.read32(messagePointer + 8);
Expand Down Expand Up @@ -690,4 +707,13 @@ void FSService::isSdmcWritable(u32 messagePointer) {
mem.write32(messagePointer, IPC::responseHeader(0x818, 2, 0));
mem.write32(messagePointer + 4, Result::Success);
mem.write8(messagePointer + 8, writeProtected ? 0 : 1);
}

void FSService::cardSlotIsInserted(u32 messagePointer) {
log("FS::CardSlotIsInserted\n");
constexpr bool cardInserted = false;

mem.write32(messagePointer, IPC::responseHeader(0x821, 2, 0));
mem.write32(messagePointer + 4, Result::Success);
mem.write8(messagePointer + 8, cardInserted ? 1 : 0);
}
1 change: 1 addition & 0 deletions src/core/services/service_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ void ServiceManager::registerClient(u32 messagePointer) {
// clang-format off
static std::map<std::string, Handle> serviceMap = {
{ "ac:u", KernelHandles::AC },
{ "act:a", KernelHandles::ACT },
{ "act:u", KernelHandles::ACT },
{ "am:app", KernelHandles::AM },
{ "APT:S", KernelHandles::APT }, // TODO: APT:A, APT:S and APT:U are slightly different
Expand Down
Loading