summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/file_sys/archive_sdmc.cpp268
-rw-r--r--src/core/file_sys/archive_sdmc.h25
-rw-r--r--src/core/file_sys/errors.h9
3 files changed, 301 insertions, 1 deletions
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index bcb03ed36..c747ba82c 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -8,6 +8,8 @@
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/file_sys/archive_sdmc.h" 9#include "core/file_sys/archive_sdmc.h"
10#include "core/file_sys/disk_archive.h" 10#include "core/file_sys/disk_archive.h"
11#include "core/file_sys/errors.h"
12#include "core/file_sys/path_parser.h"
11#include "core/settings.h" 13#include "core/settings.h"
12 14
13//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -15,6 +17,270 @@
15 17
16namespace FileSys { 18namespace FileSys {
17 19
20ResultVal<std::unique_ptr<FileBackend>> SDMCArchive::OpenFile(const Path& path,
21 const Mode& mode) const {
22 LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex);
23
24 const PathParser path_parser(path);
25
26 if (!path_parser.IsValid()) {
27 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
28 return ERROR_INVALID_PATH;
29 }
30
31 if (mode.hex == 0) {
32 LOG_ERROR(Service_FS, "Empty open mode");
33 return ERROR_INVALID_OPEN_FLAGS;
34 }
35
36 if (mode.create_flag && !mode.write_flag) {
37 LOG_ERROR(Service_FS, "Create flag set but write flag not set");
38 return ERROR_INVALID_OPEN_FLAGS;
39 }
40
41 const auto full_path = path_parser.BuildHostPath(mount_point);
42
43 switch (path_parser.GetHostStatus(mount_point)) {
44 case PathParser::InvalidMountPoint:
45 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
46 return ERROR_NOT_FOUND;
47 case PathParser::PathNotFound:
48 case PathParser::FileInPath:
49 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
50 return ERROR_NOT_FOUND;
51 case PathParser::DirectoryFound:
52 LOG_ERROR(Service_FS, "%s is not a file", full_path.c_str());
53 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC;
54 case PathParser::NotFound:
55 if (!mode.create_flag) {
56 LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.",
57 full_path.c_str());
58 return ERROR_NOT_FOUND;
59 } else {
60 // Create the file
61 FileUtil::CreateEmptyFile(full_path);
62 }
63 break;
64 }
65
66 FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb");
67 if (!file.IsOpen()) {
68 LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening %s", full_path.c_str());
69 return ERROR_NOT_FOUND;
70 }
71
72 auto disk_file = std::make_unique<DiskFile>(std::move(file), mode);
73 return MakeResult<std::unique_ptr<FileBackend>>(std::move(disk_file));
74}
75
76ResultCode SDMCArchive::DeleteFile(const Path& path) const {
77 const PathParser path_parser(path);
78
79 if (!path_parser.IsValid()) {
80 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
81 return ERROR_INVALID_PATH;
82 }
83
84 const auto full_path = path_parser.BuildHostPath(mount_point);
85
86 switch (path_parser.GetHostStatus(mount_point)) {
87 case PathParser::InvalidMountPoint:
88 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
89 return ERROR_NOT_FOUND;
90 case PathParser::PathNotFound:
91 case PathParser::FileInPath:
92 case PathParser::NotFound:
93 LOG_ERROR(Service_FS, "%s not found", full_path.c_str());
94 return ERROR_NOT_FOUND;
95 case PathParser::DirectoryFound:
96 LOG_ERROR(Service_FS, "%s is not a file", full_path.c_str());
97 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC;
98 }
99
100 if (FileUtil::Delete(full_path)) {
101 return RESULT_SUCCESS;
102 }
103
104 LOG_CRITICAL(Service_FS, "(unreachable) Unknown error deleting %s", full_path.c_str());
105 return ERROR_NOT_FOUND;
106}
107
108ResultCode SDMCArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
109 if (FileUtil::Rename(mount_point + src_path.AsString(), mount_point + dest_path.AsString())) {
110 return RESULT_SUCCESS;
111 }
112
113 // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
114 // exist or similar. Verify.
115 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
116 ErrorSummary::NothingHappened, ErrorLevel::Status);
117}
118
119template <typename T>
120static ResultCode DeleteDirectoryHelper(const Path& path, const std::string& mount_point,
121 T deleter) {
122 const PathParser path_parser(path);
123
124 if (!path_parser.IsValid()) {
125 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
126 return ERROR_INVALID_PATH;
127 }
128
129 if (path_parser.IsRootDirectory())
130 return ERROR_NOT_FOUND;
131
132 const auto full_path = path_parser.BuildHostPath(mount_point);
133
134 switch (path_parser.GetHostStatus(mount_point)) {
135 case PathParser::InvalidMountPoint:
136 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
137 return ERROR_NOT_FOUND;
138 case PathParser::PathNotFound:
139 case PathParser::NotFound:
140 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
141 return ERROR_NOT_FOUND;
142 case PathParser::FileInPath:
143 case PathParser::FileFound:
144 LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str());
145 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC;
146 }
147
148 if (deleter(full_path)) {
149 return RESULT_SUCCESS;
150 }
151
152 LOG_ERROR(Service_FS, "Directory not empty %s", full_path.c_str());
153 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC;
154}
155
156ResultCode SDMCArchive::DeleteDirectory(const Path& path) const {
157 return DeleteDirectoryHelper(path, mount_point, FileUtil::DeleteDir);
158}
159
160ResultCode SDMCArchive::DeleteDirectoryRecursively(const Path& path) const {
161 return DeleteDirectoryHelper(
162 path, mount_point, [](const std::string& p) { return FileUtil::DeleteDirRecursively(p); });
163}
164
165ResultCode SDMCArchive::CreateFile(const FileSys::Path& path, u64 size) const {
166 const PathParser path_parser(path);
167
168 if (!path_parser.IsValid()) {
169 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
170 return ERROR_INVALID_PATH;
171 }
172
173 const auto full_path = path_parser.BuildHostPath(mount_point);
174
175 switch (path_parser.GetHostStatus(mount_point)) {
176 case PathParser::InvalidMountPoint:
177 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
178 return ERROR_NOT_FOUND;
179 case PathParser::PathNotFound:
180 case PathParser::FileInPath:
181 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
182 return ERROR_NOT_FOUND;
183 case PathParser::DirectoryFound:
184 LOG_ERROR(Service_FS, "%s already exists", full_path.c_str());
185 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC;
186 case PathParser::FileFound:
187 LOG_ERROR(Service_FS, "%s already exists", full_path.c_str());
188 return ERROR_ALREADY_EXISTS;
189 }
190
191 if (size == 0) {
192 FileUtil::CreateEmptyFile(full_path);
193 return RESULT_SUCCESS;
194 }
195
196 FileUtil::IOFile file(full_path, "wb");
197 // Creates a sparse file (or a normal file on filesystems without the concept of sparse files)
198 // We do this by seeking to the right size, then writing a single null byte.
199 if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) {
200 return RESULT_SUCCESS;
201 }
202
203 LOG_ERROR(Service_FS, "Too large file");
204 return ResultCode(ErrorDescription::TooLarge, ErrorModule::FS, ErrorSummary::OutOfResource,
205 ErrorLevel::Info);
206}
207
208ResultCode SDMCArchive::CreateDirectory(const Path& path) const {
209 const PathParser path_parser(path);
210
211 if (!path_parser.IsValid()) {
212 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
213 return ERROR_INVALID_PATH;
214 }
215
216 const auto full_path = path_parser.BuildHostPath(mount_point);
217
218 switch (path_parser.GetHostStatus(mount_point)) {
219 case PathParser::InvalidMountPoint:
220 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
221 return ERROR_NOT_FOUND;
222 case PathParser::PathNotFound:
223 case PathParser::FileInPath:
224 LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str());
225 return ERROR_NOT_FOUND;
226 case PathParser::DirectoryFound:
227 case PathParser::FileFound:
228 LOG_ERROR(Service_FS, "%s already exists", full_path.c_str());
229 return ERROR_ALREADY_EXISTS;
230 }
231
232 if (FileUtil::CreateDir(mount_point + path.AsString())) {
233 return RESULT_SUCCESS;
234 }
235
236 LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", mount_point.c_str());
237 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, ErrorSummary::Canceled,
238 ErrorLevel::Status);
239}
240
241ResultCode SDMCArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
242 if (FileUtil::Rename(mount_point + src_path.AsString(), mount_point + dest_path.AsString()))
243 return RESULT_SUCCESS;
244
245 // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
246 // exist or similar. Verify.
247 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
248 ErrorSummary::NothingHappened, ErrorLevel::Status);
249}
250
251ResultVal<std::unique_ptr<DirectoryBackend>> SDMCArchive::OpenDirectory(const Path& path) const {
252 const PathParser path_parser(path);
253
254 if (!path_parser.IsValid()) {
255 LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str());
256 return ERROR_INVALID_PATH;
257 }
258
259 const auto full_path = path_parser.BuildHostPath(mount_point);
260
261 switch (path_parser.GetHostStatus(mount_point)) {
262 case PathParser::InvalidMountPoint:
263 LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str());
264 return ERROR_NOT_FOUND;
265 case PathParser::PathNotFound:
266 case PathParser::NotFound:
267 case PathParser::FileFound:
268 LOG_ERROR(Service_FS, "%s not found", full_path.c_str());
269 return ERROR_NOT_FOUND;
270 case PathParser::FileInPath:
271 LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str());
272 return ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC;
273 }
274
275 auto directory = std::make_unique<DiskDirectory>(full_path);
276 return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory));
277}
278
279u64 SDMCArchive::GetFreeBytes() const {
280 // TODO: Stubbed to return 1GiB
281 return 1024 * 1024 * 1024;
282}
283
18ArchiveFactory_SDMC::ArchiveFactory_SDMC(const std::string& sdmc_directory) 284ArchiveFactory_SDMC::ArchiveFactory_SDMC(const std::string& sdmc_directory)
19 : sdmc_directory(sdmc_directory) { 285 : sdmc_directory(sdmc_directory) {
20 LOG_INFO(Service_FS, "Directory %s set as SDMC.", sdmc_directory.c_str()); 286 LOG_INFO(Service_FS, "Directory %s set as SDMC.", sdmc_directory.c_str());
@@ -35,7 +301,7 @@ bool ArchiveFactory_SDMC::Initialize() {
35} 301}
36 302
37ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMC::Open(const Path& path) { 303ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMC::Open(const Path& path) {
38 auto archive = std::make_unique<DiskArchive>(sdmc_directory); 304 auto archive = std::make_unique<SDMCArchive>(sdmc_directory);
39 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 305 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
40} 306}
41 307
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 88e855351..4fa47ff35 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -14,6 +14,31 @@
14 14
15namespace FileSys { 15namespace FileSys {
16 16
17/// Archive backend for SDMC archive
18class SDMCArchive : public ArchiveBackend {
19public:
20 SDMCArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
21
22 std::string GetName() const override {
23 return "SDMCArchive: " + mount_point;
24 }
25
26 ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path,
27 const Mode& mode) const override;
28 ResultCode DeleteFile(const Path& path) const override;
29 ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override;
30 ResultCode DeleteDirectory(const Path& path) const override;
31 ResultCode DeleteDirectoryRecursively(const Path& path) const override;
32 ResultCode CreateFile(const Path& path, u64 size) const override;
33 ResultCode CreateDirectory(const Path& path) const override;
34 ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override;
35 ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
36 u64 GetFreeBytes() const override;
37
38protected:
39 std::string mount_point;
40};
41
17/// File system interface to the SDMC archive 42/// File system interface to the SDMC archive
18class ArchiveFactory_SDMC final : public ArchiveFactory { 43class ArchiveFactory_SDMC final : public ArchiveFactory {
19public: 44public:
diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h
index da7e82642..f9299364c 100644
--- a/src/core/file_sys/errors.h
+++ b/src/core/file_sys/errors.h
@@ -11,18 +11,27 @@ const ResultCode ERROR_INVALID_PATH(ErrorDescription::FS_InvalidPath, ErrorModul
11const ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ErrorDescription::FS_UnsupportedOpenFlags, 11const ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ErrorDescription::FS_UnsupportedOpenFlags,
12 ErrorModule::FS, ErrorSummary::NotSupported, 12 ErrorModule::FS, ErrorSummary::NotSupported,
13 ErrorLevel::Usage); 13 ErrorLevel::Usage);
14const ResultCode ERROR_INVALID_OPEN_FLAGS(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS,
15 ErrorSummary::Canceled, ErrorLevel::Status);
14const ResultCode ERROR_FILE_NOT_FOUND(ErrorDescription::FS_FileNotFound, ErrorModule::FS, 16const ResultCode ERROR_FILE_NOT_FOUND(ErrorDescription::FS_FileNotFound, ErrorModule::FS,
15 ErrorSummary::NotFound, ErrorLevel::Status); 17 ErrorSummary::NotFound, ErrorLevel::Status);
16const ResultCode ERROR_PATH_NOT_FOUND(ErrorDescription::FS_PathNotFound, ErrorModule::FS, 18const ResultCode ERROR_PATH_NOT_FOUND(ErrorDescription::FS_PathNotFound, ErrorModule::FS,
17 ErrorSummary::NotFound, ErrorLevel::Status); 19 ErrorSummary::NotFound, ErrorLevel::Status);
20const ResultCode ERROR_NOT_FOUND(ErrorDescription::FS_NotFound, ErrorModule::FS,
21 ErrorSummary::NotFound, ErrorLevel::Status);
18const ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(ErrorDescription::FS_UnexpectedFileOrDirectory, 22const ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(ErrorDescription::FS_UnexpectedFileOrDirectory,
19 ErrorModule::FS, ErrorSummary::NotSupported, 23 ErrorModule::FS, ErrorSummary::NotSupported,
20 ErrorLevel::Usage); 24 ErrorLevel::Usage);
25const ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC(ErrorDescription::FS_NotAFile,
26 ErrorModule::FS, ErrorSummary::Canceled,
27 ErrorLevel::Status);
21const ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(ErrorDescription::FS_DirectoryAlreadyExists, 28const ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(ErrorDescription::FS_DirectoryAlreadyExists,
22 ErrorModule::FS, ErrorSummary::NothingHappened, 29 ErrorModule::FS, ErrorSummary::NothingHappened,
23 ErrorLevel::Status); 30 ErrorLevel::Status);
24const ResultCode ERROR_FILE_ALREADY_EXISTS(ErrorDescription::FS_FileAlreadyExists, ErrorModule::FS, 31const ResultCode ERROR_FILE_ALREADY_EXISTS(ErrorDescription::FS_FileAlreadyExists, ErrorModule::FS,
25 ErrorSummary::NothingHappened, ErrorLevel::Status); 32 ErrorSummary::NothingHappened, ErrorLevel::Status);
33const ResultCode ERROR_ALREADY_EXISTS(ErrorDescription::FS_AlreadyExists, ErrorModule::FS,
34 ErrorSummary::NothingHappened, ErrorLevel::Status);
26const ResultCode ERROR_DIRECTORY_NOT_EMPTY(ErrorDescription::FS_DirectoryNotEmpty, ErrorModule::FS, 35const ResultCode ERROR_DIRECTORY_NOT_EMPTY(ErrorDescription::FS_DirectoryNotEmpty, ErrorModule::FS,
27 ErrorSummary::Canceled, ErrorLevel::Status); 36 ErrorSummary::Canceled, ErrorLevel::Status);
28 37