Skip to content

Commit

Permalink
Make filesystem decent, part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
wheremyfoodat committed Dec 9, 2024
1 parent 6be642a commit 812c8ff
Show file tree
Hide file tree
Showing 12 changed files with 95 additions and 56 deletions.
29 changes: 29 additions & 0 deletions include/fs/archive_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ struct FSPath {
};
}
}

bool isUTF16() const { return type == PathType::UTF16; }
bool isASCII() const { return type == PathType::ASCII; }
bool isBinary() const { return type == PathType::Binary; }
// This is not called "isEmpty()" to make obvious that we're talking about an empty-type path, NOT an empty text path
bool isEmptyType() const { return type == PathType::Empty; }

bool isTextPath() const { return isUTF16() || isASCII(); }
};

struct FilePerms {
Expand Down Expand Up @@ -259,6 +267,27 @@ class ArchiveBase {
virtual std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) = 0;

ArchiveBase(Memory& mem) : mem(mem) {}

bool isSafeTextPath(const FSPath& path) {
if (path.type == PathType::UTF16) {
return isPathSafe<PathType::UTF16>(path);
} else if (path.type == PathType::ASCII){
return isPathSafe<PathType::ASCII>(path);
}

Helpers::panic("ArchiveBase::IsSafeTextPath: Invalid path");
}

// Appends a 3DS path to an std::filesystem::path
void appendPath(std::filesystem::path& diskPath, const FSPath& guestPath) {
if (guestPath.type == PathType::UTF16) {
diskPath += std::filesystem::path(guestPath.utf16_string).make_preferred();
} else if (guestPath.type == PathType::ASCII) {
diskPath += std::filesystem::path(guestPath.string).make_preferred();
} else [[unlikely]] {
Helpers::panic("ArchiveBase::AppendPath: Invalid 3DS path");
}
}
};

struct ArchiveResource {
Expand Down
2 changes: 1 addition & 1 deletion src/core/fs/archive_card_spi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ FileDescriptor CardSPIArchive::openFile(const FSPath& path, const FilePerms& per
}

Rust::Result<ArchiveBase*, HorizonResult> CardSPIArchive::openArchive(const FSPath& path) {
if (path.type != PathType::Empty) {
if (!path.isEmptyType()) {
Helpers::panic("Unimplemented path type for CardSPIArchive::OpenArchive");
}

Expand Down
45 changes: 25 additions & 20 deletions src/core/fs/archive_ext_save_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ HorizonResult 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");
if (path.isTextPath()) {
if (!isSafeTextPath(path)) {
Helpers::panic("Unsafe path in ExtSaveData::OpenFile");
}

fs::path p = IOFile::getAppData() / backingFolder;
p += fs::path(path.utf16_string).make_preferred();
appendPath(p, path);

if (fs::exists(p))
return Result::FS::AlreadyExists;
Expand All @@ -28,17 +29,17 @@ HorizonResult ExtSaveDataArchive::createFile(const FSPath& path, u64 size) {
return Result::FS::FileTooLarge;
}

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

HorizonResult ExtSaveDataArchive::deleteFile(const FSPath& path) {
if (path.type == PathType::UTF16) {
if (!isPathSafe<PathType::UTF16>(path))
if (path.isTextPath()) {
if (!isSafeTextPath(path))
Helpers::panic("Unsafe path in ExtSaveData::DeleteFile");

fs::path p = IOFile::getAppData() / backingFolder;
p += fs::path(path.utf16_string).make_preferred();
appendPath(p, path);

if (fs::is_directory(p)) {
Helpers::panic("ExtSaveData::DeleteFile: Tried to delete directory");
Expand All @@ -65,15 +66,16 @@ HorizonResult ExtSaveDataArchive::deleteFile(const FSPath& path) {
}

FileDescriptor ExtSaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) {
if (path.type == PathType::UTF16) {
if (!isPathSafe<PathType::UTF16>(path))
if (path.isTextPath()) {
if (!isSafeTextPath(path)) {
Helpers::panic("Unsafe path in ExtSaveData::OpenFile");
}

if (perms.create())
Helpers::panic("[ExtSaveData] Can't open file with create flag");

fs::path p = IOFile::getAppData() / backingFolder;
p += fs::path(path.utf16_string).make_preferred();
appendPath(p, path);

if (fs::exists(p)) { // Return file descriptor if the file exists
IOFile file(p.string().c_str(), "r+b"); // According to Citra, this ignores the OpenFlags field and always opens as r+b? TODO: Check
Expand All @@ -88,7 +90,7 @@ FileDescriptor ExtSaveDataArchive::openFile(const FSPath& path, const FilePerms&
}

HorizonResult ExtSaveDataArchive::renameFile(const FSPath& oldPath, const FSPath& newPath) {
if (oldPath.type != PathType::UTF16 || newPath.type != PathType::UTF16) {
if (!oldPath.isUTF16() || !newPath.isUTF16()) {
Helpers::panic("Invalid path type for ExtSaveData::RenameFile");
}

Expand Down Expand Up @@ -125,15 +127,18 @@ HorizonResult ExtSaveDataArchive::renameFile(const FSPath& oldPath, const FSPath
}

HorizonResult ExtSaveDataArchive::createDirectory(const FSPath& path) {
if (path.type == PathType::UTF16) {
if (!isPathSafe<PathType::UTF16>(path)) {
if (path.isTextPath()) {
if (!isSafeTextPath(path)) {
Helpers::panic("Unsafe path in ExtSaveData::OpenFile");
}

fs::path p = IOFile::getAppData() / backingFolder;
p += fs::path(path.utf16_string).make_preferred();
appendPath(p, path);

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

if (fs::is_directory(p)) return Result::FS::AlreadyExists;
if (fs::is_regular_file(p)) {
Helpers::panic("File path passed to ExtSaveData::CreateDirectory");
}
Expand All @@ -156,7 +161,7 @@ std::string ExtSaveDataArchive::getExtSaveDataPathFromBinary(const FSPath& path)
}

Rust::Result<ArchiveBase*, HorizonResult> ExtSaveDataArchive::openArchive(const FSPath& path) {
if (path.type != PathType::Binary || path.binary.size() != 12) {
if (!path.isBinary() || path.binary.size() != 12) {
Helpers::panic("ExtSaveData accessed with an invalid path in OpenArchive");
}

Expand All @@ -172,12 +177,12 @@ Rust::Result<ArchiveBase*, HorizonResult> ExtSaveDataArchive::openArchive(const
}

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

fs::path p = IOFile::getAppData() / backingFolder;
p += fs::path(path.utf16_string).make_preferred();
appendPath(p, path);

if (fs::is_regular_file(p)) {
printf("ExtSaveData: OpenArchive used with a file path");
Expand Down
4 changes: 2 additions & 2 deletions src/core/fs/archive_ncch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ HorizonResult NCCHArchive::deleteFile(const FSPath& path) {
}

FileDescriptor NCCHArchive::openFile(const FSPath& path, const FilePerms& perms) {
if (path.type != PathType::Binary || path.binary.size() != 20) {
if (!path.isBinary() || path.binary.size() != 20) {
Helpers::panic("NCCHArchive::OpenFile: Invalid path");
}

Expand All @@ -49,7 +49,7 @@ FileDescriptor NCCHArchive::openFile(const FSPath& path, const FilePerms& perms)
}

Rust::Result<ArchiveBase*, HorizonResult> NCCHArchive::openArchive(const FSPath& path) {
if (path.type != PathType::Binary || path.binary.size() != 16) {
if (!path.isBinary() || path.binary.size() != 16) {
Helpers::panic("NCCHArchive::OpenArchive: Invalid path");
}

Expand Down
12 changes: 6 additions & 6 deletions src/core/fs/archive_save_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace fs = std::filesystem;

HorizonResult SaveDataArchive::createFile(const FSPath& path, u64 size) {
if (path.type == PathType::UTF16) {
if (path.isUTF16()) {
if (!isPathSafe<PathType::UTF16>(path))
Helpers::panic("Unsafe path in SaveData::CreateFile");

Expand Down Expand Up @@ -39,7 +39,7 @@ HorizonResult SaveDataArchive::createFile(const FSPath& path, u64 size) {
}

HorizonResult SaveDataArchive::createDirectory(const FSPath& path) {
if (path.type == PathType::UTF16) {
if (path.isUTF16()) {
if (!isPathSafe<PathType::UTF16>(path)) {
Helpers::panic("Unsafe path in SaveData::OpenFile");
}
Expand All @@ -63,7 +63,7 @@ HorizonResult SaveDataArchive::createDirectory(const FSPath& path) {
}

HorizonResult SaveDataArchive::deleteFile(const FSPath& path) {
if (path.type == PathType::UTF16) {
if (path.isUTF16()) {
if (!isPathSafe<PathType::UTF16>(path)) {
Helpers::panic("Unsafe path in SaveData::DeleteFile");
}
Expand Down Expand Up @@ -96,7 +96,7 @@ HorizonResult SaveDataArchive::deleteFile(const FSPath& path) {
}

FileDescriptor SaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) {
if (path.type == PathType::UTF16) {
if (path.isUTF16()) {
if (!isPathSafe<PathType::UTF16>(path)) {
Helpers::panic("Unsafe path in SaveData::OpenFile");
}
Expand Down Expand Up @@ -132,7 +132,7 @@ FileDescriptor SaveDataArchive::openFile(const FSPath& path, const FilePerms& pe
}

Rust::Result<DirectorySession, HorizonResult> SaveDataArchive::openDirectory(const FSPath& path) {
if (path.type == PathType::UTF16) {
if (path.isUTF16()) {
if (!isPathSafe<PathType::UTF16>(path)) {
Helpers::panic("Unsafe path in SaveData::OpenDirectory");
}
Expand Down Expand Up @@ -193,7 +193,7 @@ void SaveDataArchive::format(const FSPath& path, const ArchiveBase::FormatInfo&
}

Rust::Result<ArchiveBase*, HorizonResult> SaveDataArchive::openArchive(const FSPath& path) {
if (path.type != PathType::Empty) {
if (!path.isEmptyType()) {
Helpers::panic("Unimplemented path type for SaveData archive: %d\n", path.type);
return Err(Result::FS::NotFoundInvalid);
}
Expand Down
20 changes: 10 additions & 10 deletions src/core/fs/archive_sdmc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
namespace fs = std::filesystem;

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

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

if (fs::exists(p)) {
return Result::FS::AlreadyExists;
Expand Down Expand Up @@ -39,13 +39,13 @@ HorizonResult SDMCArchive::createFile(const FSPath& path, u64 size) {
}

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

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

if (fs::is_directory(p)) {
Helpers::panic("SDMC::DeleteFile: Tried to delete directory");
Expand Down Expand Up @@ -171,13 +171,13 @@ Rust::Result<DirectorySession, HorizonResult> SDMCArchive::openDirectory(const F
return Err(Result::FS::UnexpectedFileOrDir);
}

if (path.type == PathType::UTF16) {
if (!isPathSafe<PathType::UTF16>(path)) {
if (path.isTextPath()) {
if (!isSafeTextPath(path)) {
Helpers::panic("Unsafe path in SDMC::OpenDirectory");
}

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

if (fs::is_regular_file(p)) {
printf("SDMC: OpenDirectory used with a file path");
Expand All @@ -197,7 +197,7 @@ Rust::Result<DirectorySession, HorizonResult> SDMCArchive::openDirectory(const F

Rust::Result<ArchiveBase*, HorizonResult> SDMCArchive::openArchive(const FSPath& path) {
// TODO: Fail here if the SD is disabled in the connfig.
if (path.type != PathType::Empty) {
if (!path.isEmptyType()) {
Helpers::panic("Unimplemented path type for SDMC::OpenArchive");
}

Expand Down
4 changes: 2 additions & 2 deletions src/core/fs/archive_self_ncch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ FileDescriptor SelfNCCHArchive::openFile(const FSPath& path, const FilePerms& pe
return FileError;
}

if (path.type != PathType::Binary || path.binary.size() != 12) {
if (!path.isBinary() || path.binary.size() != 12) {
printf("Invalid SelfNCCH path type\n");
return FileError;
}
Expand All @@ -42,7 +42,7 @@ FileDescriptor SelfNCCHArchive::openFile(const FSPath& path, const FilePerms& pe
}

Rust::Result<ArchiveBase*, HorizonResult> SelfNCCHArchive::openArchive(const FSPath& path) {
if (path.type != PathType::Empty) {
if (!path.isEmptyType()) {
Helpers::panic("Invalid path type for SelfNCCH archive: %d\n", path.type);
return Err(Result::FS::NotFoundInvalid);
}
Expand Down
12 changes: 6 additions & 6 deletions src/core/fs/archive_system_save_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace fs = std::filesystem;

Rust::Result<ArchiveBase*, HorizonResult> SystemSaveDataArchive::openArchive(const FSPath& path) {
if (path.type != PathType::Binary) {
if (!path.isBinary()) {
Helpers::panic("Unimplemented path type for SystemSaveData::OpenArchive");
}

Expand All @@ -14,7 +14,7 @@ Rust::Result<ArchiveBase*, HorizonResult> SystemSaveDataArchive::openArchive(con
FileDescriptor SystemSaveDataArchive::openFile(const FSPath& path, const FilePerms& perms) {
// TODO: Validate this. Temporarily copied from SaveData archive

if (path.type == PathType::UTF16) {
if (path.isUTF16()) {
if (!isPathSafe<PathType::UTF16>(path)) {
Helpers::panic("Unsafe path in SystemSaveData::OpenFile");
}
Expand Down Expand Up @@ -50,7 +50,7 @@ FileDescriptor SystemSaveDataArchive::openFile(const FSPath& path, const FilePer
}

HorizonResult SystemSaveDataArchive::createFile(const FSPath& path, u64 size) {
if (path.type == PathType::UTF16) {
if (path.isUTF16()) {
if (!isPathSafe<PathType::UTF16>(path)) {
Helpers::panic("Unsafe path in SystemSaveData::CreateFile");
}
Expand Down Expand Up @@ -85,7 +85,7 @@ HorizonResult SystemSaveDataArchive::createFile(const FSPath& path, u64 size) {
}

HorizonResult SystemSaveDataArchive::createDirectory(const FSPath& path) {
if (path.type == PathType::UTF16) {
if (path.isUTF16()) {
if (!isPathSafe<PathType::UTF16>(path)) {
Helpers::panic("Unsafe path in SystemSaveData::CreateDirectory");
}
Expand All @@ -110,7 +110,7 @@ HorizonResult SystemSaveDataArchive::createDirectory(const FSPath& path) {


HorizonResult SystemSaveDataArchive::deleteFile(const FSPath& path) {
if (path.type == PathType::UTF16) {
if (path.isUTF16()) {
if (!isPathSafe<PathType::UTF16>(path)) {
Helpers::panic("Unsafe path in SystemSaveData::DeleteFile");
}
Expand Down Expand Up @@ -143,7 +143,7 @@ HorizonResult SystemSaveDataArchive::deleteFile(const FSPath& path) {
}

Rust::Result<DirectorySession, HorizonResult> SystemSaveDataArchive::openDirectory(const FSPath& path) {
if (path.type == PathType::UTF16) {
if (path.isUTF16()) {
if (!isPathSafe<PathType::UTF16>(path)) {
Helpers::warn("Unsafe path in SystemSaveData::OpenDirectory");
return Err(Result::FS::FileNotFoundAlt);
Expand Down
2 changes: 1 addition & 1 deletion src/core/fs/archive_twl_photo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ FileDescriptor TWLPhotoArchive::openFile(const FSPath& path, const FilePerms& pe
}

Rust::Result<ArchiveBase*, HorizonResult> TWLPhotoArchive::openArchive(const FSPath& path) {
if (path.type != PathType::Empty) {
if (!path.isEmptyType()) {
Helpers::panic("Unimplemented path type for TWLPhotoArchive::OpenArchive");
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/fs/archive_twl_sound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ FileDescriptor TWLSoundArchive::openFile(const FSPath& path, const FilePerms& pe
}

Rust::Result<ArchiveBase*, HorizonResult> TWLSoundArchive::openArchive(const FSPath& path) {
if (path.type != PathType::Empty) {
if (!path.isEmptyType()) {
Helpers::panic("Unimplemented path type for TWLSoundArchive::OpenArchive");
}

Expand Down
Loading

0 comments on commit 812c8ff

Please sign in to comment.