summaryrefslogtreecommitdiff
path: root/src/core/hle
diff options
context:
space:
mode:
authorGravatar bunnei2015-02-10 18:27:16 -0500
committerGravatar bunnei2015-02-10 18:27:16 -0500
commit27e6e6b3cb2ee1ab3a996c2b4be1d9a3c4e6b75d (patch)
treefd8b0290d4a0353c11c0e168200b20b5a89e297c /src/core/hle
parentMerge pull request #553 from lioncash/denorm (diff)
parentPTM: Fixed a problem with the gamecoin PTM file. (diff)
downloadyuzu-27e6e6b3cb2ee1ab3a996c2b4be1d9a3c4e6b75d.tar.gz
yuzu-27e6e6b3cb2ee1ab3a996c2b4be1d9a3c4e6b75d.tar.xz
yuzu-27e6e6b3cb2ee1ab3a996c2b4be1d9a3c4e6b75d.zip
Merge pull request #540 from yuriks/multi-archives
FS: Allow multiple instances of the same archive type to be open at once
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/result.h6
-rw-r--r--src/core/hle/service/fs/archive.cpp191
-rw-r--r--src/core/hle/service/fs/archive.h45
-rw-r--r--src/core/hle/service/fs/fs_user.cpp10
-rw-r--r--src/core/hle/service/ptm_u.cpp35
5 files changed, 140 insertions, 147 deletions
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 948b9e38e..9c6ca29e5 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -307,14 +307,14 @@ public:
307 } 307 }
308 308
309 ResultVal& operator=(const ResultVal& o) { 309 ResultVal& operator=(const ResultVal& o) {
310 if (*this) { 310 if (!empty()) {
311 if (o) { 311 if (!o.empty()) {
312 *GetPointer() = *o.GetPointer(); 312 *GetPointer() = *o.GetPointer();
313 } else { 313 } else {
314 GetPointer()->~T(); 314 GetPointer()->~T();
315 } 315 }
316 } else { 316 } else {
317 if (o) { 317 if (!o.empty()) {
318 new (&storage) T(*o.GetPointer()); 318 new (&storage) T(*o.GetPointer());
319 } 319 }
320 } 320 }
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index ccf132f31..e197d3599 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -5,6 +5,8 @@
5#include <memory> 5#include <memory>
6#include <unordered_map> 6#include <unordered_map>
7 7
8#include <boost/container/flat_map.hpp>
9
8#include "common/common_types.h" 10#include "common/common_types.h"
9#include "common/file_util.h" 11#include "common/file_util.h"
10#include "common/make_unique.h" 12#include "common/make_unique.h"
@@ -18,7 +20,6 @@
18#include "core/file_sys/archive_sdmc.h" 20#include "core/file_sys/archive_sdmc.h"
19#include "core/file_sys/directory_backend.h" 21#include "core/file_sys/directory_backend.h"
20#include "core/hle/service/fs/archive.h" 22#include "core/hle/service/fs/archive.h"
21#include "core/hle/kernel/session.h"
22#include "core/hle/result.h" 23#include "core/hle/result.h"
23 24
24// Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map. 25// Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map.
@@ -74,43 +75,19 @@ enum class DirectoryCommand : u32 {
74 Close = 0x08020000, 75 Close = 0x08020000,
75}; 76};
76 77
77class Archive { 78ResultVal<bool> File::SyncRequest() {
78public: 79 u32* cmd_buff = Kernel::GetCommandBuffer();
79 Archive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) 80 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
80 : id_code(id_code), backend(std::move(backend)) { 81 switch (cmd) {
81 }
82
83 std::string GetName() const { return "Archive: " + backend->GetName(); }
84
85 ArchiveIdCode id_code; ///< Id code of the archive
86 std::unique_ptr<FileSys::ArchiveBackend> backend; ///< Archive backend interface
87};
88
89class File : public Kernel::Session {
90public:
91 File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path)
92 : path(path), priority(0), backend(std::move(backend)) {
93 }
94
95 std::string GetName() const override { return "Path: " + path.DebugStr(); }
96
97 FileSys::Path path; ///< Path of the file
98 u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means
99 std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface
100
101 ResultVal<bool> SyncRequest() override {
102 u32* cmd_buff = Kernel::GetCommandBuffer();
103 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
104 switch (cmd) {
105 82
106 // Read from file... 83 // Read from file...
107 case FileCommand::Read: 84 case FileCommand::Read:
108 { 85 {
109 u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; 86 u64 offset = cmd_buff[1] | ((u64)cmd_buff[2]) << 32;
110 u32 length = cmd_buff[3]; 87 u32 length = cmd_buff[3];
111 u32 address = cmd_buff[5]; 88 u32 address = cmd_buff[5];
112 LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x", 89 LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x",
113 GetTypeName().c_str(), GetName().c_str(), offset, length, address); 90 GetTypeName().c_str(), GetName().c_str(), offset, length, address);
114 cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); 91 cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address));
115 break; 92 break;
116 } 93 }
@@ -118,12 +95,12 @@ public:
118 // Write to file... 95 // Write to file...
119 case FileCommand::Write: 96 case FileCommand::Write:
120 { 97 {
121 u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; 98 u64 offset = cmd_buff[1] | ((u64)cmd_buff[2]) << 32;
122 u32 length = cmd_buff[3]; 99 u32 length = cmd_buff[3];
123 u32 flush = cmd_buff[4]; 100 u32 flush = cmd_buff[4];
124 u32 address = cmd_buff[6]; 101 u32 address = cmd_buff[6];
125 LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", 102 LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
126 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); 103 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
127 cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); 104 cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address));
128 break; 105 break;
129 } 106 }
@@ -141,7 +118,7 @@ public:
141 { 118 {
142 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); 119 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
143 LOG_TRACE(Service_FS, "SetSize %s %s size=%llu", 120 LOG_TRACE(Service_FS, "SetSize %s %s size=%llu",
144 GetTypeName().c_str(), GetName().c_str(), size); 121 GetTypeName().c_str(), GetName().c_str(), size);
145 backend->SetSize(size); 122 backend->SetSize(size);
146 break; 123 break;
147 } 124 }
@@ -187,27 +164,15 @@ public:
187 ResultCode error = UnimplementedFunction(ErrorModule::FS); 164 ResultCode error = UnimplementedFunction(ErrorModule::FS);
188 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. 165 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
189 return error; 166 return error;
190 }
191 cmd_buff[1] = 0; // No error
192 return MakeResult<bool>(false);
193 } 167 }
194}; 168 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
195 169 return MakeResult<bool>(false);
196class Directory : public Kernel::Session { 170}
197public:
198 Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path)
199 : path(path), backend(std::move(backend)) {
200 }
201
202 std::string GetName() const override { return "Directory: " + path.DebugStr(); }
203
204 FileSys::Path path; ///< Path of the directory
205 std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface
206 171
207 ResultVal<bool> SyncRequest() override { 172ResultVal<bool> Directory::SyncRequest() {
208 u32* cmd_buff = Kernel::GetCommandBuffer(); 173 u32* cmd_buff = Kernel::GetCommandBuffer();
209 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); 174 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
210 switch (cmd) { 175 switch (cmd) {
211 176
212 // Read from directory... 177 // Read from directory...
213 case DirectoryCommand::Read: 178 case DirectoryCommand::Read:
@@ -216,7 +181,7 @@ public:
216 u32 address = cmd_buff[3]; 181 u32 address = cmd_buff[3];
217 auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); 182 auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address));
218 LOG_TRACE(Service_FS, "Read %s %s: count=%d", 183 LOG_TRACE(Service_FS, "Read %s %s: count=%d",
219 GetTypeName().c_str(), GetName().c_str(), count); 184 GetTypeName().c_str(), GetName().c_str(), count);
220 185
221 // Number of entries actually read 186 // Number of entries actually read
222 cmd_buff[2] = backend->Read(count, entries); 187 cmd_buff[2] = backend->Read(count, entries);
@@ -236,29 +201,31 @@ public:
236 ResultCode error = UnimplementedFunction(ErrorModule::FS); 201 ResultCode error = UnimplementedFunction(ErrorModule::FS);
237 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. 202 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
238 return MakeResult<bool>(false); 203 return MakeResult<bool>(false);
239 }
240 cmd_buff[1] = 0; // No error
241 return MakeResult<bool>(false);
242 } 204 }
243}; 205 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
206 return MakeResult<bool>(false);
207}
244 208
245//////////////////////////////////////////////////////////////////////////////////////////////////// 209////////////////////////////////////////////////////////////////////////////////////////////////////
246 210
211using FileSys::ArchiveBackend;
212using FileSys::ArchiveFactory;
213
247/** 214/**
248 * Map of registered archives, identified by id code. Once an archive is registered here, it is 215 * Map of registered archives, identified by id code. Once an archive is registered here, it is
249 * never removed until the FS service is shut down. 216 * never removed until the FS service is shut down.
250 */ 217 */
251static std::unordered_map<ArchiveIdCode, std::unique_ptr<Archive>> id_code_map; 218static boost::container::flat_map<ArchiveIdCode, std::unique_ptr<ArchiveFactory>> id_code_map;
252 219
253/** 220/**
254 * Map of active archive handles. Values are pointers to the archives in `idcode_map`. 221 * Map of active archive handles. Values are pointers to the archives in `idcode_map`.
255 */ 222 */
256static std::unordered_map<ArchiveHandle, Archive*> handle_map; 223static std::unordered_map<ArchiveHandle, std::unique_ptr<ArchiveBackend>> handle_map;
257static ArchiveHandle next_handle; 224static ArchiveHandle next_handle;
258 225
259static Archive* GetArchive(ArchiveHandle handle) { 226static ArchiveBackend* GetArchive(ArchiveHandle handle) {
260 auto itr = handle_map.find(handle); 227 auto itr = handle_map.find(handle);
261 return (itr == handle_map.end()) ? nullptr : itr->second; 228 return (itr == handle_map.end()) ? nullptr : itr->second.get();
262} 229}
263 230
264ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path) { 231ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path) {
@@ -271,15 +238,13 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi
271 ErrorSummary::NotFound, ErrorLevel::Permanent); 238 ErrorSummary::NotFound, ErrorLevel::Permanent);
272 } 239 }
273 240
274 ResultCode res = itr->second->backend->Open(archive_path); 241 CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path));
275 if (!res.IsSuccess())
276 return res;
277 242
278 // This should never even happen in the first place with 64-bit handles, 243 // This should never even happen in the first place with 64-bit handles,
279 while (handle_map.count(next_handle) != 0) { 244 while (handle_map.count(next_handle) != 0) {
280 ++next_handle; 245 ++next_handle;
281 } 246 }
282 handle_map.emplace(next_handle, itr->second.get()); 247 handle_map.emplace(next_handle, std::move(res));
283 return MakeResult<ArchiveHandle>(next_handle++); 248 return MakeResult<ArchiveHandle>(next_handle++);
284} 249}
285 250
@@ -292,39 +257,39 @@ ResultCode CloseArchive(ArchiveHandle handle) {
292 257
293// TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in 258// TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in
294// http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22 259// http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22
295ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) { 260ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory, ArchiveIdCode id_code) {
296 auto result = id_code_map.emplace(id_code, Common::make_unique<Archive>(std::move(backend), id_code)); 261 auto result = id_code_map.emplace(id_code, std::move(factory));
297 262
298 bool inserted = result.second; 263 bool inserted = result.second;
299 _dbg_assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code"); 264 _assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code");
300 265
301 auto& archive = result.first->second; 266 auto& archive = result.first->second;
302 LOG_DEBUG(Service_FS, "Registered archive %s with id code 0x%08X", archive->GetName().c_str(), id_code); 267 LOG_DEBUG(Service_FS, "Registered archive %s with id code 0x%08X", archive->GetName().c_str(), id_code);
303 return RESULT_SUCCESS; 268 return RESULT_SUCCESS;
304} 269}
305 270
306ResultVal<Kernel::SharedPtr<Kernel::Session>> OpenFileFromArchive(ArchiveHandle archive_handle, 271ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
307 const FileSys::Path& path, const FileSys::Mode mode) { 272 const FileSys::Path& path, const FileSys::Mode mode) {
308 Archive* archive = GetArchive(archive_handle); 273 ArchiveBackend* archive = GetArchive(archive_handle);
309 if (archive == nullptr) 274 if (archive == nullptr)
310 return ERR_INVALID_HANDLE; 275 return ERR_INVALID_HANDLE;
311 276
312 std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); 277 std::unique_ptr<FileSys::FileBackend> backend = archive->OpenFile(path, mode);
313 if (backend == nullptr) { 278 if (backend == nullptr) {
314 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, 279 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS,
315 ErrorSummary::NotFound, ErrorLevel::Status); 280 ErrorSummary::NotFound, ErrorLevel::Status);
316 } 281 }
317 282
318 auto file = Kernel::SharedPtr<File>(new File(std::move(backend), path)); 283 auto file = Kernel::SharedPtr<File>(new File(std::move(backend), path));
319 return MakeResult<Kernel::SharedPtr<Kernel::Session>>(std::move(file)); 284 return MakeResult<Kernel::SharedPtr<File>>(std::move(file));
320} 285}
321 286
322ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { 287ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) {
323 Archive* archive = GetArchive(archive_handle); 288 ArchiveBackend* archive = GetArchive(archive_handle);
324 if (archive == nullptr) 289 if (archive == nullptr)
325 return ERR_INVALID_HANDLE; 290 return ERR_INVALID_HANDLE;
326 291
327 if (archive->backend->DeleteFile(path)) 292 if (archive->DeleteFile(path))
328 return RESULT_SUCCESS; 293 return RESULT_SUCCESS;
329 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description 294 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
330 ErrorSummary::Canceled, ErrorLevel::Status); 295 ErrorSummary::Canceled, ErrorLevel::Status);
@@ -332,13 +297,13 @@ ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Pa
332 297
333ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, 298ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path,
334 ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { 299 ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) {
335 Archive* src_archive = GetArchive(src_archive_handle); 300 ArchiveBackend* src_archive = GetArchive(src_archive_handle);
336 Archive* dest_archive = GetArchive(dest_archive_handle); 301 ArchiveBackend* dest_archive = GetArchive(dest_archive_handle);
337 if (src_archive == nullptr || dest_archive == nullptr) 302 if (src_archive == nullptr || dest_archive == nullptr)
338 return ERR_INVALID_HANDLE; 303 return ERR_INVALID_HANDLE;
339 304
340 if (src_archive == dest_archive) { 305 if (src_archive == dest_archive) {
341 if (src_archive->backend->RenameFile(src_path, dest_path)) 306 if (src_archive->RenameFile(src_path, dest_path))
342 return RESULT_SUCCESS; 307 return RESULT_SUCCESS;
343 } else { 308 } else {
344 // TODO: Implement renaming across archives 309 // TODO: Implement renaming across archives
@@ -352,30 +317,30 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const Fil
352} 317}
353 318
354ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { 319ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) {
355 Archive* archive = GetArchive(archive_handle); 320 ArchiveBackend* archive = GetArchive(archive_handle);
356 if (archive == nullptr) 321 if (archive == nullptr)
357 return ERR_INVALID_HANDLE; 322 return ERR_INVALID_HANDLE;
358 323
359 if (archive->backend->DeleteDirectory(path)) 324 if (archive->DeleteDirectory(path))
360 return RESULT_SUCCESS; 325 return RESULT_SUCCESS;
361 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description 326 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
362 ErrorSummary::Canceled, ErrorLevel::Status); 327 ErrorSummary::Canceled, ErrorLevel::Status);
363} 328}
364 329
365ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u32 file_size) { 330ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u32 file_size) {
366 Archive* archive = GetArchive(archive_handle); 331 ArchiveBackend* archive = GetArchive(archive_handle);
367 if (archive == nullptr) 332 if (archive == nullptr)
368 return ERR_INVALID_HANDLE; 333 return ERR_INVALID_HANDLE;
369 334
370 return archive->backend->CreateFile(path, file_size); 335 return archive->CreateFile(path, file_size);
371} 336}
372 337
373ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { 338ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) {
374 Archive* archive = GetArchive(archive_handle); 339 ArchiveBackend* archive = GetArchive(archive_handle);
375 if (archive == nullptr) 340 if (archive == nullptr)
376 return ERR_INVALID_HANDLE; 341 return ERR_INVALID_HANDLE;
377 342
378 if (archive->backend->CreateDirectory(path)) 343 if (archive->CreateDirectory(path))
379 return RESULT_SUCCESS; 344 return RESULT_SUCCESS;
380 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description 345 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
381 ErrorSummary::Canceled, ErrorLevel::Status); 346 ErrorSummary::Canceled, ErrorLevel::Status);
@@ -383,13 +348,13 @@ ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy
383 348
384ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, 349ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path,
385 ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { 350 ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) {
386 Archive* src_archive = GetArchive(src_archive_handle); 351 ArchiveBackend* src_archive = GetArchive(src_archive_handle);
387 Archive* dest_archive = GetArchive(dest_archive_handle); 352 ArchiveBackend* dest_archive = GetArchive(dest_archive_handle);
388 if (src_archive == nullptr || dest_archive == nullptr) 353 if (src_archive == nullptr || dest_archive == nullptr)
389 return ERR_INVALID_HANDLE; 354 return ERR_INVALID_HANDLE;
390 355
391 if (src_archive == dest_archive) { 356 if (src_archive == dest_archive) {
392 if (src_archive->backend->RenameDirectory(src_path, dest_path)) 357 if (src_archive->RenameDirectory(src_path, dest_path))
393 return RESULT_SUCCESS; 358 return RESULT_SUCCESS;
394 } else { 359 } else {
395 // TODO: Implement renaming across archives 360 // TODO: Implement renaming across archives
@@ -402,31 +367,29 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons
402 ErrorSummary::NothingHappened, ErrorLevel::Status); 367 ErrorSummary::NothingHappened, ErrorLevel::Status);
403} 368}
404 369
405ResultVal<Kernel::SharedPtr<Kernel::Session>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, 370ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
406 const FileSys::Path& path) { 371 const FileSys::Path& path) {
407 Archive* archive = GetArchive(archive_handle); 372 ArchiveBackend* archive = GetArchive(archive_handle);
408 if (archive == nullptr) 373 if (archive == nullptr)
409 return ERR_INVALID_HANDLE; 374 return ERR_INVALID_HANDLE;
410 375
411 std::unique_ptr<FileSys::DirectoryBackend> backend = archive->backend->OpenDirectory(path); 376 std::unique_ptr<FileSys::DirectoryBackend> backend = archive->OpenDirectory(path);
412 if (backend == nullptr) { 377 if (backend == nullptr) {
413 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, 378 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
414 ErrorSummary::NotFound, ErrorLevel::Permanent); 379 ErrorSummary::NotFound, ErrorLevel::Permanent);
415 } 380 }
416 381
417 auto directory = Kernel::SharedPtr<Directory>(new Directory(std::move(backend), path)); 382 auto directory = Kernel::SharedPtr<Directory>(new Directory(std::move(backend), path));
418 return MakeResult<Kernel::SharedPtr<Kernel::Session>>(std::move(directory)); 383 return MakeResult<Kernel::SharedPtr<Directory>>(std::move(directory));
419} 384}
420 385
421ResultCode FormatSaveData() { 386ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) {
422 // Do not create the archive again if it already exists 387 auto archive_itr = id_code_map.find(id_code);
423 auto archive_itr = id_code_map.find(ArchiveIdCode::SaveData);
424 if (archive_itr == id_code_map.end()) { 388 if (archive_itr == id_code_map.end()) {
425 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error 389 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
426 } 390 }
427 391
428 // Use an empty path, we do not use it when formatting the savedata 392 return archive_itr->second->Format(path);
429 return archive_itr->second->backend->Format(FileSys::Path());
430} 393}
431 394
432ResultCode CreateExtSaveData(u32 high, u32 low) { 395ResultCode CreateExtSaveData(u32 high, u32 low) {
@@ -460,32 +423,32 @@ void ArchiveInit() {
460 423
461 std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); 424 std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX);
462 std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); 425 std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX);
463 auto sdmc_archive = Common::make_unique<FileSys::Archive_SDMC>(sdmc_directory); 426 auto sdmc_factory = Common::make_unique<FileSys::ArchiveFactory_SDMC>(sdmc_directory);
464 if (sdmc_archive->Initialize()) 427 if (sdmc_factory->Initialize())
465 CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC); 428 RegisterArchiveType(std::move(sdmc_factory), ArchiveIdCode::SDMC);
466 else 429 else
467 LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); 430 LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
468 431
469 // Create the SaveData archive 432 // Create the SaveData archive
470 auto savedata_archive = Common::make_unique<FileSys::Archive_SaveData>(sdmc_directory); 433 auto savedata_factory = Common::make_unique<FileSys::ArchiveFactory_SaveData>(sdmc_directory);
471 CreateArchive(std::move(savedata_archive), ArchiveIdCode::SaveData); 434 RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData);
472 435
473 auto extsavedata_archive = Common::make_unique<FileSys::Archive_ExtSaveData>(sdmc_directory, false); 436 auto extsavedata_factory = Common::make_unique<FileSys::ArchiveFactory_ExtSaveData>(sdmc_directory, false);
474 if (extsavedata_archive->Initialize()) 437 if (extsavedata_factory->Initialize())
475 CreateArchive(std::move(extsavedata_archive), ArchiveIdCode::ExtSaveData); 438 RegisterArchiveType(std::move(extsavedata_factory), ArchiveIdCode::ExtSaveData);
476 else 439 else
477 LOG_ERROR(Service_FS, "Can't instantiate ExtSaveData archive with path %s", extsavedata_archive->GetMountPoint().c_str()); 440 LOG_ERROR(Service_FS, "Can't instantiate ExtSaveData archive with path %s", extsavedata_factory->GetMountPoint().c_str());
478 441
479 auto sharedextsavedata_archive = Common::make_unique<FileSys::Archive_ExtSaveData>(nand_directory, true); 442 auto sharedextsavedata_factory = Common::make_unique<FileSys::ArchiveFactory_ExtSaveData>(nand_directory, true);
480 if (sharedextsavedata_archive->Initialize()) 443 if (sharedextsavedata_factory->Initialize())
481 CreateArchive(std::move(sharedextsavedata_archive), ArchiveIdCode::SharedExtSaveData); 444 RegisterArchiveType(std::move(sharedextsavedata_factory), ArchiveIdCode::SharedExtSaveData);
482 else 445 else
483 LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s", 446 LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s",
484 sharedextsavedata_archive->GetMountPoint().c_str()); 447 sharedextsavedata_factory->GetMountPoint().c_str());
485 448
486 // Create the SaveDataCheck archive, basically a small variation of the RomFS archive 449 // Create the SaveDataCheck archive, basically a small variation of the RomFS archive
487 auto savedatacheck_archive = Common::make_unique<FileSys::Archive_SaveDataCheck>(nand_directory); 450 auto savedatacheck_factory = Common::make_unique<FileSys::ArchiveFactory_SaveDataCheck>(nand_directory);
488 CreateArchive(std::move(savedatacheck_archive), ArchiveIdCode::SaveDataCheck); 451 RegisterArchiveType(std::move(savedatacheck_factory), ArchiveIdCode::SaveDataCheck);
489} 452}
490 453
491/// Shutdown archives 454/// Shutdown archives
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index ab5ea4da8..c490327d0 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -8,6 +8,7 @@
8 8
9#include "core/file_sys/archive_backend.h" 9#include "core/file_sys/archive_backend.h"
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/session.h"
11#include "core/hle/result.h" 12#include "core/hle/result.h"
12 13
13/// The unique system identifier hash, also known as ID0 14/// The unique system identifier hash, also known as ID0
@@ -36,6 +37,35 @@ enum class ArchiveIdCode : u32 {
36 37
37typedef u64 ArchiveHandle; 38typedef u64 ArchiveHandle;
38 39
40class File : public Kernel::Session {
41public:
42 File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path)
43 : path(path), priority(0), backend(std::move(backend)) {
44 }
45
46 std::string GetName() const override { return "Path: " + path.DebugStr(); }
47
48 FileSys::Path path; ///< Path of the file
49 u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means
50 std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface
51
52 ResultVal<bool> SyncRequest() override;
53};
54
55class Directory : public Kernel::Session {
56public:
57 Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path)
58 : path(path), backend(std::move(backend)) {
59 }
60
61 std::string GetName() const override { return "Directory: " + path.DebugStr(); }
62
63 FileSys::Path path; ///< Path of the directory
64 std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface
65
66 ResultVal<bool> SyncRequest() override;
67};
68
39/** 69/**
40 * Opens an archive 70 * Opens an archive
41 * @param id_code IdCode of the archive to open 71 * @param id_code IdCode of the archive to open
@@ -51,11 +81,11 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi
51ResultCode CloseArchive(ArchiveHandle handle); 81ResultCode CloseArchive(ArchiveHandle handle);
52 82
53/** 83/**
54 * Creates an Archive 84 * Registers an Archive type, instances of which can later be opened using its IdCode.
55 * @param backend File system backend interface to the archive 85 * @param backend File system backend interface to the archive
56 * @param id_code Id code used to access this type of archive 86 * @param id_code Id code used to access this type of archive
57 */ 87 */
58ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code); 88ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory, ArchiveIdCode id_code);
59 89
60/** 90/**
61 * Open a File from an Archive 91 * Open a File from an Archive
@@ -64,7 +94,7 @@ ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, Arc
64 * @param mode Mode under which to open the File 94 * @param mode Mode under which to open the File
65 * @return The opened File object as a Session 95 * @return The opened File object as a Session
66 */ 96 */
67ResultVal<Kernel::SharedPtr<Kernel::Session>> OpenFileFromArchive(ArchiveHandle archive_handle, 97ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
68 const FileSys::Path& path, const FileSys::Mode mode); 98 const FileSys::Path& path, const FileSys::Mode mode);
69 99
70/** 100/**
@@ -128,14 +158,17 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons
128 * @param path Path to the Directory inside of the Archive 158 * @param path Path to the Directory inside of the Archive
129 * @return The opened Directory object as a Session 159 * @return The opened Directory object as a Session
130 */ 160 */
131ResultVal<Kernel::SharedPtr<Kernel::Session>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, 161ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
132 const FileSys::Path& path); 162 const FileSys::Path& path);
133 163
134/** 164/**
135 * Creates a blank SaveData archive. 165 * Erases the contents of the physical folder that contains the archive
166 * identified by the specified id code and path
167 * @param id_code The id of the archive to format
168 * @param path The path to the archive, if relevant.
136 * @return ResultCode 0 on success or the corresponding code on error 169 * @return ResultCode 0 on success or the corresponding code on error
137 */ 170 */
138ResultCode FormatSaveData(); 171ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = FileSys::Path());
139 172
140/** 173/**
141 * Creates a blank SharedExtSaveData archive for the specified extdata ID 174 * Creates a blank SharedExtSaveData archive for the specified extdata ID
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index 94a3a31c8..71ee4ff55 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -61,7 +61,7 @@ static void OpenFile(Service::Interface* self) {
61 61
62 LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); 62 LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes);
63 63
64 ResultVal<SharedPtr<Session>> file_res = OpenFileFromArchive(archive_handle, file_path, mode); 64 ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(archive_handle, file_path, mode);
65 cmd_buff[1] = file_res.Code().raw; 65 cmd_buff[1] = file_res.Code().raw;
66 if (file_res.Succeeded()) { 66 if (file_res.Succeeded()) {
67 cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); 67 cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom();
@@ -117,7 +117,7 @@ static void OpenFileDirectly(Service::Interface* self) {
117 } 117 }
118 SCOPE_EXIT({ CloseArchive(*archive_handle); }); 118 SCOPE_EXIT({ CloseArchive(*archive_handle); });
119 119
120 ResultVal<SharedPtr<Session>> file_res = OpenFileFromArchive(*archive_handle, file_path, mode); 120 ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(*archive_handle, file_path, mode);
121 cmd_buff[1] = file_res.Code().raw; 121 cmd_buff[1] = file_res.Code().raw;
122 if (file_res.Succeeded()) { 122 if (file_res.Succeeded()) {
123 cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); 123 cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom();
@@ -337,7 +337,7 @@ static void OpenDirectory(Service::Interface* self) {
337 337
338 LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); 338 LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
339 339
340 ResultVal<SharedPtr<Session>> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path); 340 ResultVal<SharedPtr<Directory>> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path);
341 cmd_buff[1] = dir_res.Code().raw; 341 cmd_buff[1] = dir_res.Code().raw;
342 if (dir_res.Succeeded()) { 342 if (dir_res.Succeeded()) {
343 cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom(); 343 cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom();
@@ -468,7 +468,7 @@ static void FormatSaveData(Service::Interface* self) {
468 return; 468 return;
469 } 469 }
470 470
471 cmd_buff[1] = FormatSaveData().raw; 471 cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw;
472} 472}
473 473
474/** 474/**
@@ -484,7 +484,7 @@ static void FormatThisUserSaveData(Service::Interface* self) {
484 484
485 // TODO(Subv): Find out what the inputs and outputs of this function are 485 // TODO(Subv): Find out what the inputs and outputs of this function are
486 486
487 cmd_buff[1] = FormatSaveData().raw; 487 cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw;
488} 488}
489 489
490static void CreateExtSaveData(Service::Interface* self) { 490static void CreateExtSaveData(Service::Interface* self) {
diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp
index 7b465a348..7c8d9ce8c 100644
--- a/src/core/hle/service/ptm_u.cpp
+++ b/src/core/hle/service/ptm_u.cpp
@@ -4,8 +4,9 @@
4 4
5#include "common/log.h" 5#include "common/log.h"
6#include "common/make_unique.h" 6#include "common/make_unique.h"
7#include "core/file_sys/archive_extsavedata.h" 7
8#include "core/hle/hle.h" 8#include "core/hle/hle.h"
9#include "core/hle/service/fs/archive.h"
9#include "core/hle/service/ptm_u.h" 10#include "core/hle/service/ptm_u.h"
10 11
11//////////////////////////////////////////////////////////////////////////////////////////////////// 12////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -28,7 +29,6 @@ struct GameCoin {
28 u8 day; 29 u8 day;
29}; 30};
30static const GameCoin default_game_coin = { 0x4F00, 42, 0, 0, 0, 2014, 12, 29 }; 31static const GameCoin default_game_coin = { 0x4F00, 42, 0, 0, 0, 2014, 12, 29 };
31static std::unique_ptr<FileSys::Archive_ExtSaveData> ptm_shared_extsavedata;
32static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0}; 32static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0};
33 33
34/// Charge levels used by PTM functions 34/// Charge levels used by PTM functions
@@ -138,31 +138,28 @@ const Interface::FunctionInfo FunctionTable[] = {
138 138
139Interface::Interface() { 139Interface::Interface() {
140 Register(FunctionTable); 140 Register(FunctionTable);
141 // Create the SharedExtSaveData archive 0xF000000B and the gamecoin.dat file 141
142 // TODO(Subv): In the future we should use the FS service to query this archive 142 // Open the SharedExtSaveData archive 0xF000000B and the gamecoin.dat file
143 std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX);
144 ptm_shared_extsavedata = Common::make_unique<FileSys::Archive_ExtSaveData>(nand_directory, true);
145 if (!ptm_shared_extsavedata->Initialize()) {
146 LOG_CRITICAL(Service_PTM, "Could not initialize SharedExtSaveData archive for the PTM:U service");
147 return;
148 }
149 FileSys::Path archive_path(ptm_shared_extdata_id); 143 FileSys::Path archive_path(ptm_shared_extdata_id);
150 ResultCode result = ptm_shared_extsavedata->Open(archive_path); 144 auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path);
151 // If the archive didn't exist, create the files inside 145 // If the archive didn't exist, create the files inside
152 if (result.description == ErrorDescription::FS_NotFormatted) { 146 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
153 // Format the archive to clear the directories 147 // Format the archive to create the directories
154 ptm_shared_extsavedata->Format(archive_path); 148 Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path);
155 // Open it again to get a valid archive now that the folder exists 149 // Open it again to get a valid archive now that the folder exists
156 ptm_shared_extsavedata->Open(archive_path); 150 archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path);
151 _assert_msg_(Service_PTM, archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!");
152
157 FileSys::Path gamecoin_path("gamecoin.dat"); 153 FileSys::Path gamecoin_path("gamecoin.dat");
158 FileSys::Mode open_mode = {}; 154 FileSys::Mode open_mode = {};
159 open_mode.write_flag = 1; 155 open_mode.write_flag = 1;
160 open_mode.create_flag = 1; 156 open_mode.create_flag = 1;
161 // Open the file and write the default gamecoin information 157 // Open the file and write the default gamecoin information
162 auto gamecoin = ptm_shared_extsavedata->OpenFile(gamecoin_path, open_mode); 158 auto gamecoin_result = Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode);
163 if (gamecoin != nullptr) { 159 if (gamecoin_result.Succeeded()) {
164 gamecoin->Write(0, sizeof(GameCoin), 1, reinterpret_cast<const u8*>(&default_game_coin)); 160 auto gamecoin = gamecoin_result.MoveFrom();
165 gamecoin->Close(); 161 gamecoin->backend->Write(0, sizeof(GameCoin), 1, reinterpret_cast<const u8*>(&default_game_coin));
162 gamecoin->backend->Close();
166 } 163 }
167 } 164 }
168} 165}