summaryrefslogtreecommitdiff
path: root/src/core/file_sys
diff options
context:
space:
mode:
authorGravatar Subv2014-12-16 00:33:41 -0500
committerGravatar Subv2014-12-17 19:21:38 -0500
commitea9ce0fba776eef8f9e4f3a86e71256091732a14 (patch)
tree9e698ba00993a4aff1df4d60f9fcf3cf135ee76c /src/core/file_sys
parentMerge pull request #293 from lioncash/sops (diff)
downloadyuzu-ea9ce0fba776eef8f9e4f3a86e71256091732a14.tar.gz
yuzu-ea9ce0fba776eef8f9e4f3a86e71256091732a14.tar.xz
yuzu-ea9ce0fba776eef8f9e4f3a86e71256091732a14.zip
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')
-rw-r--r--src/core/file_sys/archive_savedata.cpp33
-rw-r--r--src/core/file_sys/archive_savedata.h32
-rw-r--r--src/core/file_sys/archive_sdmc.cpp83
-rw-r--r--src/core/file_sys/archive_sdmc.h66
-rw-r--r--src/core/file_sys/directory_sdmc.cpp88
-rw-r--r--src/core/file_sys/directory_sdmc.h55
-rw-r--r--src/core/file_sys/disk_archive.cpp167
-rw-r--r--src/core/file_sys/disk_archive.h101
-rw-r--r--src/core/file_sys/file_backend.h5
-rw-r--r--src/core/file_sys/file_romfs.h2
-rw-r--r--src/core/file_sys/file_sdmc.cpp110
-rw-r--r--src/core/file_sys/file_sdmc.h75
12 files changed, 344 insertions, 473 deletions
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
new file mode 100644
index 000000000..2414564e4
--- /dev/null
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -0,0 +1,33 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2+
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/archive_savedata.h"
11#include "core/file_sys/disk_archive.h"
12#include "core/settings.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace
16
17namespace FileSys {
18
19Archive_SaveData::Archive_SaveData(const std::string& mount_point, u64 program_id)
20 : DiskArchive(mount_point + Common::StringFromFormat("%016X", program_id) + DIR_SEP) {
21 LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str());
22}
23
24bool Archive_SaveData::Initialize() {
25 if (!FileUtil::CreateFullPath(mount_point)) {
26 LOG_ERROR(Service_FS, "Unable to create SaveData path.");
27 return false;
28 }
29
30 return true;
31}
32
33} // namespace FileSys
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h
new file mode 100644
index 000000000..b3e561130
--- /dev/null
+++ b/src/core/file_sys/archive_savedata.h
@@ -0,0 +1,32 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2+
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/file_sys/disk_archive.h"
10#include "core/loader/loader.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace
14
15namespace FileSys {
16
17/// File system interface to the SaveData archive
18class Archive_SaveData final : public DiskArchive {
19public:
20 Archive_SaveData(const std::string& mount_point, u64 program_id);
21
22 /**
23 * Initialize the archive.
24 * @return CreateSaveDataResult AlreadyExists if the SaveData folder already exists,
25 * Success if it was created properly and Failure if there was any error
26 */
27 bool Initialize();
28
29 std::string GetName() const override { return "SaveData"; }
30};
31
32} // namespace FileSys
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index 9d58668e0..dccdf7f67 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -8,8 +8,7 @@
8#include "common/file_util.h" 8#include "common/file_util.h"
9 9
10#include "core/file_sys/archive_sdmc.h" 10#include "core/file_sys/archive_sdmc.h"
11#include "core/file_sys/directory_sdmc.h" 11#include "core/file_sys/disk_archive.h"
12#include "core/file_sys/file_sdmc.h"
13#include "core/settings.h" 12#include "core/settings.h"
14 13
15//////////////////////////////////////////////////////////////////////////////////////////////////// 14////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -17,18 +16,10 @@
17 16
18namespace FileSys { 17namespace FileSys {
19 18
20Archive_SDMC::Archive_SDMC(const std::string& mount_point) { 19Archive_SDMC::Archive_SDMC(const std::string& mount_point) : DiskArchive(mount_point) {
21 this->mount_point = mount_point;
22 LOG_INFO(Service_FS, "Directory %s set as SDMC.", mount_point.c_str()); 20 LOG_INFO(Service_FS, "Directory %s set as SDMC.", mount_point.c_str());
23} 21}
24 22
25Archive_SDMC::~Archive_SDMC() {
26}
27
28/**
29 * Initialize the archive.
30 * @return true if it initialized successfully
31 */
32bool Archive_SDMC::Initialize() { 23bool Archive_SDMC::Initialize() {
33 if (!Settings::values.use_virtual_sd) { 24 if (!Settings::values.use_virtual_sd) {
34 LOG_WARNING(Service_FS, "SDMC disabled by config."); 25 LOG_WARNING(Service_FS, "SDMC disabled by config.");
@@ -43,74 +34,4 @@ bool Archive_SDMC::Initialize() {
43 return true; 34 return true;
44} 35}
45 36
46/**
47 * Open a file specified by its path, using the specified mode
48 * @param path Path relative to the archive
49 * @param mode Mode to open the file with
50 * @return Opened file, or nullptr
51 */
52std::unique_ptr<FileBackend> Archive_SDMC::OpenFile(const Path& path, const Mode mode) const {
53 LOG_DEBUG(Service_FS, "called path=%s mode=%u", path.DebugStr().c_str(), mode.hex);
54 File_SDMC* file = new File_SDMC(this, path, mode);
55 if (!file->Open())
56 return nullptr;
57 return std::unique_ptr<FileBackend>(file);
58}
59
60/**
61 * Delete a file specified by its path
62 * @param path Path relative to the archive
63 * @return Whether the file could be deleted
64 */
65bool Archive_SDMC::DeleteFile(const FileSys::Path& path) const {
66 return FileUtil::Delete(GetMountPoint() + path.AsString());
67}
68
69bool Archive_SDMC::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
70 return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
71}
72
73/**
74 * Delete a directory specified by its path
75 * @param path Path relative to the archive
76 * @return Whether the directory could be deleted
77 */
78bool Archive_SDMC::DeleteDirectory(const FileSys::Path& path) const {
79 return FileUtil::DeleteDir(GetMountPoint() + path.AsString());
80}
81
82/**
83 * Create a directory specified by its path
84 * @param path Path relative to the archive
85 * @return Whether the directory could be created
86 */
87bool Archive_SDMC::CreateDirectory(const Path& path) const {
88 return FileUtil::CreateDir(GetMountPoint() + path.AsString());
89}
90
91bool Archive_SDMC::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
92 return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
93}
94
95/**
96 * Open a directory specified by its path
97 * @param path Path relative to the archive
98 * @return Opened directory, or nullptr
99 */
100std::unique_ptr<DirectoryBackend> Archive_SDMC::OpenDirectory(const Path& path) const {
101 LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str());
102 Directory_SDMC* directory = new Directory_SDMC(this, path);
103 if (!directory->Open())
104 return nullptr;
105 return std::unique_ptr<DirectoryBackend>(directory);
106}
107
108/**
109 * Getter for the path used for this Archive
110 * @return Mount point of that passthrough archive
111 */
112std::string Archive_SDMC::GetMountPoint() const {
113 return mount_point;
114}
115
116} // namespace FileSys 37} // namespace FileSys
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 059045245..c84c6948e 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -6,7 +6,7 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9#include "core/file_sys/archive_backend.h" 9#include "core/file_sys/disk_archive.h"
10#include "core/loader/loader.h" 10#include "core/loader/loader.h"
11 11
12//////////////////////////////////////////////////////////////////////////////////////////////////// 12////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -15,10 +15,9 @@
15namespace FileSys { 15namespace FileSys {
16 16
17/// File system interface to the SDMC archive 17/// File system interface to the SDMC archive
18class Archive_SDMC final : public ArchiveBackend { 18class Archive_SDMC final : public DiskArchive {
19public: 19public:
20 Archive_SDMC(const std::string& mount_point); 20 Archive_SDMC(const std::string& mount_point);
21 ~Archive_SDMC() override;
22 21
23 /** 22 /**
24 * Initialize the archive. 23 * Initialize the archive.
@@ -27,67 +26,6 @@ public:
27 bool Initialize(); 26 bool Initialize();
28 27
29 std::string GetName() const override { return "SDMC"; } 28 std::string GetName() const override { return "SDMC"; }
30
31 /**
32 * Open a file specified by its path, using the specified mode
33 * @param path Path relative to the archive
34 * @param mode Mode to open the file with
35 * @return Opened file, or nullptr
36 */
37 std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override;
38
39 /**
40 * Delete a file specified by its path
41 * @param path Path relative to the archive
42 * @return Whether the file could be deleted
43 */
44 bool DeleteFile(const FileSys::Path& path) const override;
45
46 /**
47 * Rename a File specified by its path
48 * @param src_path Source path relative to the archive
49 * @param dest_path Destination path relative to the archive
50 * @return Whether rename succeeded
51 */
52 bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
53
54 /**
55 * Delete a directory specified by its path
56 * @param path Path relative to the archive
57 * @return Whether the directory could be deleted
58 */
59 bool DeleteDirectory(const FileSys::Path& path) const override;
60
61 /**
62 * Create a directory specified by its path
63 * @param path Path relative to the archive
64 * @return Whether the directory could be created
65 */
66 bool CreateDirectory(const Path& path) const override;
67
68 /**
69 * Rename a Directory specified by its path
70 * @param src_path Source path relative to the archive
71 * @param dest_path Destination path relative to the archive
72 * @return Whether rename succeeded
73 */
74 bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
75
76 /**
77 * Open a directory specified by its path
78 * @param path Path relative to the archive
79 * @return Opened directory, or nullptr
80 */
81 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
82
83 /**
84 * Getter for the path used for this Archive
85 * @return Mount point of that passthrough archive
86 */
87 std::string GetMountPoint() const;
88
89private:
90 std::string mount_point;
91}; 29};
92 30
93} // namespace FileSys 31} // namespace FileSys
diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp
deleted file mode 100644
index 519787641..000000000
--- a/src/core/file_sys/directory_sdmc.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/directory_sdmc.h"
11#include "core/file_sys/archive_sdmc.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const Path& path) {
19 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
20 // the root directory we set while opening the archive.
21 // For example, opening /../../usr/bin can give the emulated program your installed programs.
22 this->path = archive->GetMountPoint() + path.AsString();
23
24}
25
26Directory_SDMC::~Directory_SDMC() {
27 Close();
28}
29
30bool Directory_SDMC::Open() {
31 if (!FileUtil::IsDirectory(path))
32 return false;
33 FileUtil::ScanDirectoryTree(path, directory);
34 children_iterator = directory.children.begin();
35 return true;
36}
37
38/**
39 * List files contained in the directory
40 * @param count Number of entries to return at once in entries
41 * @param entries Buffer to read data into
42 * @return Number of entries listed
43 */
44u32 Directory_SDMC::Read(const u32 count, Entry* entries) {
45 u32 entries_read = 0;
46
47 while (entries_read < count && children_iterator != directory.children.cend()) {
48 const FileUtil::FSTEntry& file = *children_iterator;
49 const std::string& filename = file.virtualName;
50 Entry& entry = entries[entries_read];
51
52 LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
53
54 // TODO(Link Mauve): use a proper conversion to UTF-16.
55 for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
56 entry.filename[j] = filename[j];
57 if (!filename[j])
58 break;
59 }
60
61 FileUtil::SplitFilename83(filename, entry.short_name, entry.extension);
62
63 entry.is_directory = file.isDirectory;
64 entry.is_hidden = (filename[0] == '.');
65 entry.is_read_only = 0;
66 entry.file_size = file.size;
67
68 // We emulate a SD card where the archive bit has never been cleared, as it would be on
69 // most user SD cards.
70 // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a
71 // file bit.
72 entry.is_archive = !file.isDirectory;
73
74 ++entries_read;
75 ++children_iterator;
76 }
77 return entries_read;
78}
79
80/**
81 * Close the directory
82 * @return true if the directory closed correctly
83 */
84bool Directory_SDMC::Close() const {
85 return true;
86}
87
88} // namespace FileSys
diff --git a/src/core/file_sys/directory_sdmc.h b/src/core/file_sys/directory_sdmc.h
deleted file mode 100644
index 407a256ef..000000000
--- a/src/core/file_sys/directory_sdmc.h
+++ /dev/null
@@ -1,55 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/directory_backend.h"
11#include "core/file_sys/archive_sdmc.h"
12#include "core/loader/loader.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace
16
17namespace FileSys {
18
19class Directory_SDMC final : public DirectoryBackend {
20public:
21 Directory_SDMC();
22 Directory_SDMC(const Archive_SDMC* archive, const Path& path);
23 ~Directory_SDMC() override;
24
25 /**
26 * Open the directory
27 * @return true if the directory opened correctly
28 */
29 bool Open() override;
30
31 /**
32 * List files contained in the directory
33 * @param count Number of entries to return at once in entries
34 * @param entries Buffer to read data into
35 * @return Number of entries listed
36 */
37 u32 Read(const u32 count, Entry* entries) override;
38
39 /**
40 * Close the directory
41 * @return true if the directory closed correctly
42 */
43 bool Close() const override;
44
45private:
46 std::string path;
47 u32 total_entries_in_directory;
48 FileUtil::FSTEntry directory;
49
50 // We need to remember the last entry we returned, so a subsequent call to Read will continue
51 // from the next one. This iterator will always point to the next unread entry.
52 std::vector<FileUtil::FSTEntry>::iterator children_iterator;
53};
54
55} // namespace FileSys
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp
new file mode 100644
index 000000000..eabf58057
--- /dev/null
+++ b/src/core/file_sys/disk_archive.cpp
@@ -0,0 +1,167 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/disk_archive.h"
11#include "core/settings.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18std::unique_ptr<FileBackend> DiskArchive::OpenFile(const Path& path, const Mode mode) const {
19 LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex);
20 DiskFile* file = new DiskFile(this, path, mode);
21 if (!file->Open())
22 return nullptr;
23 return std::unique_ptr<FileBackend>(file);
24}
25
26bool DiskArchive::DeleteFile(const FileSys::Path& path) const {
27 return FileUtil::Delete(GetMountPoint() + path.AsString());
28}
29
30bool DiskArchive::RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
31 return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
32}
33
34bool DiskArchive::DeleteDirectory(const FileSys::Path& path) const {
35 return FileUtil::DeleteDir(GetMountPoint() + path.AsString());
36}
37
38bool DiskArchive::CreateDirectory(const Path& path) const {
39 return FileUtil::CreateDir(GetMountPoint() + path.AsString());
40}
41
42bool DiskArchive::RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const {
43 return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
44}
45
46std::unique_ptr<DirectoryBackend> DiskArchive::OpenDirectory(const Path& path) const {
47 LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str());
48 DiskDirectory* directory = new DiskDirectory(this, path);
49 if (!directory->Open())
50 return nullptr;
51 return std::unique_ptr<DirectoryBackend>(directory);
52}
53
54////////////////////////////////////////////////////////////////////////////////////////////////////
55
56DiskFile::DiskFile(const DiskArchive* archive, const Path& path, const Mode mode) {
57 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
58 // the root directory we set while opening the archive.
59 // For example, opening /../../etc/passwd can give the emulated program your users list.
60 this->path = archive->GetMountPoint() + path.AsString();
61 this->mode.hex = mode.hex;
62 this->archive = archive;
63}
64
65bool DiskFile::Open() {
66 if (!mode.create_flag && !FileUtil::Exists(path)) {
67 LOG_ERROR(Service_FS, "Non-existing file %s can’t be open without mode create.", path.c_str());
68 return false;
69 }
70
71 std::string mode_string;
72 if (mode.create_flag)
73 mode_string = "w+";
74 else if (mode.write_flag)
75 mode_string = "r+"; // Files opened with Write access can be read from
76 else if (mode.read_flag)
77 mode_string = "r";
78
79 // Open the file in binary mode, to avoid problems with CR/LF on Windows systems
80 mode_string += "b";
81
82 file = new FileUtil::IOFile(path, mode_string.c_str());
83 return true;
84}
85
86size_t DiskFile::Read(const u64 offset, const u32 length, u8* buffer) const {
87 file->Seek(offset, SEEK_SET);
88 return file->ReadBytes(buffer, length);
89}
90
91size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
92 file->Seek(offset, SEEK_SET);
93 size_t written = file->WriteBytes(buffer, length);
94 if (flush)
95 file->Flush();
96 return written;
97}
98
99size_t DiskFile::GetSize() const {
100 return static_cast<size_t>(file->GetSize());
101}
102
103bool DiskFile::SetSize(const u64 size) const {
104 file->Resize(size);
105 file->Flush();
106 return true;
107}
108
109bool DiskFile::Close() const {
110 return file->Close();
111}
112
113////////////////////////////////////////////////////////////////////////////////////////////////////
114
115DiskDirectory::DiskDirectory(const DiskArchive* archive, const Path& path) {
116 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
117 // the root directory we set while opening the archive.
118 // For example, opening /../../usr/bin can give the emulated program your installed programs.
119 this->path = archive->GetMountPoint() + path.AsString();
120 this->archive = archive;
121}
122
123bool DiskDirectory::Open() {
124 if (!FileUtil::IsDirectory(path))
125 return false;
126 FileUtil::ScanDirectoryTree(path, directory);
127 children_iterator = directory.children.begin();
128 return true;
129}
130
131u32 DiskDirectory::Read(const u32 count, Entry* entries) {
132 u32 entries_read = 0;
133
134 while (entries_read < count && children_iterator != directory.children.cend()) {
135 const FileUtil::FSTEntry& file = *children_iterator;
136 const std::string& filename = file.virtualName;
137 Entry& entry = entries[entries_read];
138
139 LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
140
141 // TODO(Link Mauve): use a proper conversion to UTF-16.
142 for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
143 entry.filename[j] = filename[j];
144 if (!filename[j])
145 break;
146 }
147
148 FileUtil::SplitFilename83(filename, entry.short_name, entry.extension);
149
150 entry.is_directory = file.isDirectory;
151 entry.is_hidden = (filename[0] == '.');
152 entry.is_read_only = 0;
153 entry.file_size = file.size;
154
155 // We emulate a SD card where the archive bit has never been cleared, as it would be on
156 // most user SD cards.
157 // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a
158 // file bit.
159 entry.is_archive = !file.isDirectory;
160
161 ++entries_read;
162 ++children_iterator;
163 }
164 return entries_read;
165}
166
167} // namespace FileSys
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h
new file mode 100644
index 000000000..778c83953
--- /dev/null
+++ b/src/core/file_sys/disk_archive.h
@@ -0,0 +1,101 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/file_sys/archive_backend.h"
10#include "core/loader/loader.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace
14
15namespace FileSys {
16
17/**
18 * Helper which implements a backend accessing the host machine's filesystem.
19 * This should be subclassed by concrete archive types, which will provide the
20 * base directory on the host filesystem and override any required functionality.
21 */
22class DiskArchive : public ArchiveBackend {
23public:
24 DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
25
26 virtual std::string GetName() const = 0;
27 std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override;
28 bool DeleteFile(const FileSys::Path& path) const override;
29 bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
30 bool DeleteDirectory(const FileSys::Path& path) const override;
31 bool CreateDirectory(const Path& path) const override;
32 bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const override;
33 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
34
35 /**
36 * Getter for the path used for this Archive
37 * @return Mount point of that passthrough archive
38 */
39 const std::string& GetMountPoint() const {
40 return mount_point;
41 }
42
43protected:
44 std::string mount_point;
45};
46
47class DiskFile : public FileBackend {
48public:
49 DiskFile();
50 DiskFile(const DiskArchive* archive, const Path& path, const Mode mode);
51
52 ~DiskFile() override {
53 Close();
54 }
55
56 bool Open() override;
57 size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
58 size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
59 size_t GetSize() const override;
60 bool SetSize(const u64 size) const override;
61 bool Close() const override;
62
63 void Flush() const override {
64 file->Flush();
65 }
66
67protected:
68 const DiskArchive* archive;
69 std::string path;
70 Mode mode;
71 FileUtil::IOFile* file;
72};
73
74class DiskDirectory : public DirectoryBackend {
75public:
76 DiskDirectory();
77 DiskDirectory(const DiskArchive* archive, const Path& path);
78
79 ~DiskDirectory() override {
80 Close();
81 }
82
83 bool Open() override;
84 u32 Read(const u32 count, Entry* entries) override;
85
86 bool Close() const override {
87 return true;
88 }
89
90protected:
91 const DiskArchive* archive;
92 std::string path;
93 u32 total_entries_in_directory;
94 FileUtil::FSTEntry directory;
95
96 // We need to remember the last entry we returned, so a subsequent call to Read will continue
97 // from the next one. This iterator will always point to the next unread entry.
98 std::vector<FileUtil::FSTEntry>::iterator children_iterator;
99};
100
101} // namespace FileSys
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h
index 1b81d5fe9..539ec7314 100644
--- a/src/core/file_sys/file_backend.h
+++ b/src/core/file_sys/file_backend.h
@@ -61,6 +61,11 @@ public:
61 * @return true if the file closed correctly 61 * @return true if the file closed correctly
62 */ 62 */
63 virtual bool Close() const = 0; 63 virtual bool Close() const = 0;
64
65 /**
66 * Flushes the file
67 */
68 virtual void Flush() const = 0;
64}; 69};
65 70
66} // namespace FileSys 71} // namespace FileSys
diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h
index 09fa2e7e3..32fa6b6d3 100644
--- a/src/core/file_sys/file_romfs.h
+++ b/src/core/file_sys/file_romfs.h
@@ -64,6 +64,8 @@ public:
64 */ 64 */
65 bool Close() const override; 65 bool Close() const override;
66 66
67 void Flush() const override { }
68
67private: 69private:
68 const Archive_RomFS* archive; 70 const Archive_RomFS* archive;
69}; 71};
diff --git a/src/core/file_sys/file_sdmc.cpp b/src/core/file_sys/file_sdmc.cpp
deleted file mode 100644
index 46c29900b..000000000
--- a/src/core/file_sys/file_sdmc.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/file_sdmc.h"
11#include "core/file_sys/archive_sdmc.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18File_SDMC::File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode) {
19 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
20 // the root directory we set while opening the archive.
21 // For example, opening /../../etc/passwd can give the emulated program your users list.
22 this->path = archive->GetMountPoint() + path.AsString();
23 this->mode.hex = mode.hex;
24}
25
26File_SDMC::~File_SDMC() {
27 Close();
28}
29
30/**
31 * Open the file
32 * @return true if the file opened correctly
33 */
34bool File_SDMC::Open() {
35 if (!mode.create_flag && !FileUtil::Exists(path)) {
36 LOG_ERROR(Service_FS, "Non-existing file %s can’t be open without mode create.", path.c_str());
37 return false;
38 }
39
40 std::string mode_string;
41 if (mode.create_flag)
42 mode_string = "w+";
43 else if (mode.write_flag)
44 mode_string = "r+"; // Files opened with Write access can be read from
45 else if (mode.read_flag)
46 mode_string = "r";
47
48 // Open the file in binary mode, to avoid problems with CR/LF on Windows systems
49 mode_string += "b";
50
51 file = new FileUtil::IOFile(path, mode_string.c_str());
52 return true;
53}
54
55/**
56 * Read data from the file
57 * @param offset Offset in bytes to start reading data from
58 * @param length Length in bytes of data to read from file
59 * @param buffer Buffer to read data into
60 * @return Number of bytes read
61 */
62size_t File_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const {
63 file->Seek(offset, SEEK_SET);
64 return file->ReadBytes(buffer, length);
65}
66
67/**
68 * Write data to the file
69 * @param offset Offset in bytes to start writing data to
70 * @param length Length in bytes of data to write to file
71 * @param flush The flush parameters (0 == do not flush)
72 * @param buffer Buffer to read data from
73 * @return Number of bytes written
74 */
75size_t File_SDMC::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
76 file->Seek(offset, SEEK_SET);
77 size_t written = file->WriteBytes(buffer, length);
78 if (flush)
79 file->Flush();
80 return written;
81}
82
83/**
84 * Get the size of the file in bytes
85 * @return Size of the file in bytes
86 */
87size_t File_SDMC::GetSize() const {
88 return static_cast<size_t>(file->GetSize());
89}
90
91/**
92 * Set the size of the file in bytes
93 * @param size New size of the file
94 * @return true if successful
95 */
96bool File_SDMC::SetSize(const u64 size) const {
97 file->Resize(size);
98 file->Flush();
99 return true;
100}
101
102/**
103 * Close the file
104 * @return true if the file closed correctly
105 */
106bool File_SDMC::Close() const {
107 return file->Close();
108}
109
110} // namespace FileSys
diff --git a/src/core/file_sys/file_sdmc.h b/src/core/file_sys/file_sdmc.h
deleted file mode 100644
index e01548598..000000000
--- a/src/core/file_sys/file_sdmc.h
+++ /dev/null
@@ -1,75 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/file_backend.h"
11#include "core/file_sys/archive_sdmc.h"
12#include "core/loader/loader.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace
16
17namespace FileSys {
18
19class File_SDMC final : public FileBackend {
20public:
21 File_SDMC();
22 File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode);
23 ~File_SDMC() override;
24
25 /**
26 * Open the file
27 * @return true if the file opened correctly
28 */
29 bool Open() override;
30
31 /**
32 * Read data from the file
33 * @param offset Offset in bytes to start reading data from
34 * @param length Length in bytes of data to read from file
35 * @param buffer Buffer to read data into
36 * @return Number of bytes read
37 */
38 size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
39
40 /**
41 * Write data to the file
42 * @param offset Offset in bytes to start writing data to
43 * @param length Length in bytes of data to write to file
44 * @param flush The flush parameters (0 == do not flush)
45 * @param buffer Buffer to read data from
46 * @return Number of bytes written
47 */
48 size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
49
50 /**
51 * Get the size of the file in bytes
52 * @return Size of the file in bytes
53 */
54 size_t GetSize() const override;
55
56 /**
57 * Set the size of the file in bytes
58 * @param size New size of the file
59 * @return true if successful
60 */
61 bool SetSize(const u64 size) const override;
62
63 /**
64 * Close the file
65 * @return true if the file closed correctly
66 */
67 bool Close() const override;
68
69private:
70 std::string path;
71 Mode mode;
72 FileUtil::IOFile* file;
73};
74
75} // namespace FileSys