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

Make filesystem decent, part 1 #677

Merged
merged 1 commit into from
Dec 9, 2024
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
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
Loading