aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/file_sys/disk_archive.cpp
diff options
context:
space:
mode:
authorGravatar Subv <subv2112@gmail.com>2014-12-16 00:33:41 -0500
committerGravatar Subv <subv2112@gmail.com>2014-12-17 19:21:38 -0500
commitea9ce0fba776eef8f9e4f3a86e71256091732a14 (patch)
tree9e698ba00993a4aff1df4d60f9fcf3cf135ee76c /src/core/file_sys/disk_archive.cpp
parente6f440ea7f4d5f8c075a5735747ef8facbb4699a (diff)
Filesystem/Archives: Implemented the SaveData archive
The savedata for each game is stored in /savedata/<ProgramID> for NCCH files. ELF files and 3DSX files use the folder 0 because they have no ID information Got rid of the code duplication in File and Directory Files that deal with the host machine's file system now live in DiskFile, similarly for directories and DiskDirectory and archives with DiskArchive. FS_U: Use the correct error code when a file wasn't found
Diffstat (limited to 'src/core/file_sys/disk_archive.cpp')
-rw-r--r--src/core/file_sys/disk_archive.cpp167
1 files changed, 167 insertions, 0 deletions
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp
new file mode 100644
index 00000000..eabf5805
--- /dev/null
+++ b/src/core/file_sys/disk_archive.cpp
@@ -0,0 +1,167 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include <sys/stat.h>
+
+#include "common/common_types.h"
+#include "common/file_util.h"
+
+#include "core/file_sys/disk_archive.h"
+#include "core/settings.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+std::unique_ptr<FileBackend> DiskArchive::OpenFile(const Path& path, const Mode mode) const {
+ LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex);
+ DiskFile* file = new DiskFile(this, path, mode);
+ if (!file->Open())
+ return nullptr;
+ return std::unique_ptr<FileBackend>(file);
+}
+
+bool DiskArchive::DeleteFile(const FileSys::Path& path) const {
+ return FileUtil::Delete(GetMountPoint() + path.AsString());
+}
+
+bool DiskArchive::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
+ return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
+}
+
+bool DiskArchive::DeleteDirectory(const FileSys::Path& path) const {
+ return FileUtil::DeleteDir(GetMountPoint() + path.AsString());
+}
+
+bool DiskArchive::CreateDirectory(const Path& path) const {
+ return FileUtil::CreateDir(GetMountPoint() + path.AsString());
+}
+
+bool DiskArchive::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
+ return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
+}
+
+std::unique_ptr<DirectoryBackend> DiskArchive::OpenDirectory(const Path& path) const {
+ LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str());
+ DiskDirectory* directory = new DiskDirectory(this, path);
+ if (!directory->Open())
+ return nullptr;
+ return std::unique_ptr<DirectoryBackend>(directory);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+DiskFile::DiskFile(const DiskArchive* archive, const Path& path, const Mode mode) {
+ // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
+ // the root directory we set while opening the archive.
+ // For example, opening /../../etc/passwd can give the emulated program your users list.
+ this->path = archive->GetMountPoint() + path.AsString();
+ this->mode.hex = mode.hex;
+ this->archive = archive;
+}
+
+bool DiskFile::Open() {
+ if (!mode.create_flag && !FileUtil::Exists(path)) {
+ LOG_ERROR(Service_FS, "Non-existing file %s can’t be open without mode create.", path.c_str());
+ return false;
+ }
+
+ std::string mode_string;
+ if (mode.create_flag)
+ mode_string = "w+";
+ else if (mode.write_flag)
+ mode_string = "r+"; // Files opened with Write access can be read from
+ else if (mode.read_flag)
+ mode_string = "r";
+
+ // Open the file in binary mode, to avoid problems with CR/LF on Windows systems
+ mode_string += "b";
+
+ file = new FileUtil::IOFile(path, mode_string.c_str());
+ return true;
+}
+
+size_t DiskFile::Read(const u64 offset, const u32 length, u8* buffer) const {
+ file->Seek(offset, SEEK_SET);
+ return file->ReadBytes(buffer, length);
+}
+
+size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
+ file->Seek(offset, SEEK_SET);
+ size_t written = file->WriteBytes(buffer, length);
+ if (flush)
+ file->Flush();
+ return written;
+}
+
+size_t DiskFile::GetSize() const {
+ return static_cast<size_t>(file->GetSize());
+}
+
+bool DiskFile::SetSize(const u64 size) const {
+ file->Resize(size);
+ file->Flush();
+ return true;
+}
+
+bool DiskFile::Close() const {
+ return file->Close();
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+DiskDirectory::DiskDirectory(const DiskArchive* archive, const Path& path) {
+ // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
+ // the root directory we set while opening the archive.
+ // For example, opening /../../usr/bin can give the emulated program your installed programs.
+ this->path = archive->GetMountPoint() + path.AsString();
+ this->archive = archive;
+}
+
+bool DiskDirectory::Open() {
+ if (!FileUtil::IsDirectory(path))
+ return false;
+ FileUtil::ScanDirectoryTree(path, directory);
+ children_iterator = directory.children.begin();
+ return true;
+}
+
+u32 DiskDirectory::Read(const u32 count, Entry* entries) {
+ u32 entries_read = 0;
+
+ while (entries_read < count && children_iterator != directory.children.cend()) {
+ const FileUtil::FSTEntry& file = *children_iterator;
+ const std::string& filename = file.virtualName;
+ Entry& entry = entries[entries_read];
+
+ LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
+
+ // TODO(Link Mauve): use a proper conversion to UTF-16.
+ for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
+ entry.filename[j] = filename[j];
+ if (!filename[j])
+ break;
+ }
+
+ FileUtil::SplitFilename83(filename, entry.short_name, entry.extension);
+
+ entry.is_directory = file.isDirectory;
+ entry.is_hidden = (filename[0] == '.');
+ entry.is_read_only = 0;
+ entry.file_size = file.size;
+
+ // We emulate a SD card where the archive bit has never been cleared, as it would be on
+ // most user SD cards.
+ // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a
+ // file bit.
+ entry.is_archive = !file.isDirectory;
+
+ ++entries_read;
+ ++children_iterator;
+ }
+ return entries_read;
+}
+
+} // namespace FileSys