diff options
| author | 2014-12-15 22:15:08 -0500 | |
|---|---|---|
| committer | 2014-12-15 22:15:08 -0500 | |
| commit | cd2a31eaf4a35568a18840eba7d3cdac59881d2f (patch) | |
| tree | 37a4d61adebae300e8ef172538c6a2d2eae80ff1 /src/core/hle/service | |
| parent | Update README.md (diff) | |
| parent | Work around libstdc++'s lack of support for std::hash on enums (diff) | |
| download | yuzu-cd2a31eaf4a35568a18840eba7d3cdac59881d2f.tar.gz yuzu-cd2a31eaf4a35568a18840eba7d3cdac59881d2f.tar.xz yuzu-cd2a31eaf4a35568a18840eba7d3cdac59881d2f.zip | |
Merge pull request #283 from yuriks/archive-refactor
Archive refactor
Diffstat (limited to 'src/core/hle/service')
| -rw-r--r-- | src/core/hle/service/fs/archive.cpp | 392 | ||||
| -rw-r--r-- | src/core/hle/service/fs/archive.h | 119 | ||||
| -rw-r--r-- | src/core/hle/service/fs/fs_user.cpp (renamed from src/core/hle/service/fs_user.cpp) | 130 | ||||
| -rw-r--r-- | src/core/hle/service/fs/fs_user.h (renamed from src/core/hle/service/fs_user.h) | 12 | ||||
| -rw-r--r-- | src/core/hle/service/service.cpp | 4 |
5 files changed, 598 insertions, 59 deletions
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp new file mode 100644 index 000000000..caf82d556 --- /dev/null +++ b/src/core/hle/service/fs/archive.cpp | |||
| @@ -0,0 +1,392 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <memory> | ||
| 6 | #include <unordered_map> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/file_util.h" | ||
| 10 | #include "common/math_util.h" | ||
| 11 | |||
| 12 | #include "core/file_sys/archive_backend.h" | ||
| 13 | #include "core/file_sys/archive_sdmc.h" | ||
| 14 | #include "core/file_sys/directory_backend.h" | ||
| 15 | #include "core/hle/service/fs/archive.h" | ||
| 16 | #include "core/hle/kernel/session.h" | ||
| 17 | #include "core/hle/result.h" | ||
| 18 | |||
| 19 | // Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map. | ||
| 20 | // Workaroung for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970 | ||
| 21 | namespace std { | ||
| 22 | template <> | ||
| 23 | struct hash<Service::FS::ArchiveIdCode> { | ||
| 24 | typedef Service::FS::ArchiveIdCode argument_type; | ||
| 25 | typedef std::size_t result_type; | ||
| 26 | |||
| 27 | result_type operator()(const argument_type& id_code) const { | ||
| 28 | typedef std::underlying_type<argument_type>::type Type; | ||
| 29 | return std::hash<Type>()(static_cast<Type>(id_code)); | ||
| 30 | } | ||
| 31 | }; | ||
| 32 | } | ||
| 33 | |||
| 34 | namespace Service { | ||
| 35 | namespace FS { | ||
| 36 | |||
| 37 | // Command to access archive file | ||
| 38 | enum class FileCommand : u32 { | ||
| 39 | Dummy1 = 0x000100C6, | ||
| 40 | Control = 0x040100C4, | ||
| 41 | OpenSubFile = 0x08010100, | ||
| 42 | Read = 0x080200C2, | ||
| 43 | Write = 0x08030102, | ||
| 44 | GetSize = 0x08040000, | ||
| 45 | SetSize = 0x08050080, | ||
| 46 | GetAttributes = 0x08060000, | ||
| 47 | SetAttributes = 0x08070040, | ||
| 48 | Close = 0x08080000, | ||
| 49 | Flush = 0x08090000, | ||
| 50 | }; | ||
| 51 | |||
| 52 | // Command to access directory | ||
| 53 | enum class DirectoryCommand : u32 { | ||
| 54 | Dummy1 = 0x000100C6, | ||
| 55 | Control = 0x040100C4, | ||
| 56 | Read = 0x08010042, | ||
| 57 | Close = 0x08020000, | ||
| 58 | }; | ||
| 59 | |||
| 60 | class Archive { | ||
| 61 | public: | ||
| 62 | Archive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) | ||
| 63 | : backend(std::move(backend)), id_code(id_code) { | ||
| 64 | } | ||
| 65 | |||
| 66 | std::string GetName() const { return "Archive: " + backend->GetName(); } | ||
| 67 | |||
| 68 | ArchiveIdCode id_code; ///< Id code of the archive | ||
| 69 | std::unique_ptr<FileSys::ArchiveBackend> backend; ///< Archive backend interface | ||
| 70 | }; | ||
| 71 | |||
| 72 | class File : public Kernel::Session { | ||
| 73 | public: | ||
| 74 | File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path) | ||
| 75 | : backend(std::move(backend)), path(path) { | ||
| 76 | } | ||
| 77 | |||
| 78 | std::string GetName() const override { return "Path: " + path.DebugStr(); } | ||
| 79 | |||
| 80 | FileSys::Path path; ///< Path of the file | ||
| 81 | std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface | ||
| 82 | |||
| 83 | ResultVal<bool> SyncRequest() override { | ||
| 84 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 85 | FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); | ||
| 86 | switch (cmd) { | ||
| 87 | |||
| 88 | // Read from file... | ||
| 89 | case FileCommand::Read: | ||
| 90 | { | ||
| 91 | u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; | ||
| 92 | u32 length = cmd_buff[3]; | ||
| 93 | u32 address = cmd_buff[5]; | ||
| 94 | LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x", | ||
| 95 | GetTypeName().c_str(), GetName().c_str(), offset, length, address); | ||
| 96 | cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | |||
| 100 | // Write to file... | ||
| 101 | case FileCommand::Write: | ||
| 102 | { | ||
| 103 | u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; | ||
| 104 | u32 length = cmd_buff[3]; | ||
| 105 | u32 flush = cmd_buff[4]; | ||
| 106 | u32 address = cmd_buff[6]; | ||
| 107 | LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", | ||
| 108 | GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); | ||
| 109 | cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); | ||
| 110 | break; | ||
| 111 | } | ||
| 112 | |||
| 113 | case FileCommand::GetSize: | ||
| 114 | { | ||
| 115 | LOG_TRACE(Service_FS, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str()); | ||
| 116 | u64 size = backend->GetSize(); | ||
| 117 | cmd_buff[2] = (u32)size; | ||
| 118 | cmd_buff[3] = size >> 32; | ||
| 119 | break; | ||
| 120 | } | ||
| 121 | |||
| 122 | case FileCommand::SetSize: | ||
| 123 | { | ||
| 124 | u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); | ||
| 125 | LOG_TRACE(Service_FS, "SetSize %s %s size=%llu", | ||
| 126 | GetTypeName().c_str(), GetName().c_str(), size); | ||
| 127 | backend->SetSize(size); | ||
| 128 | break; | ||
| 129 | } | ||
| 130 | |||
| 131 | case FileCommand::Close: | ||
| 132 | { | ||
| 133 | LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); | ||
| 134 | Kernel::g_object_pool.Destroy<File>(GetHandle()); | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | |||
| 138 | // Unknown command... | ||
| 139 | default: | ||
| 140 | LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); | ||
| 141 | ResultCode error = UnimplementedFunction(ErrorModule::FS); | ||
| 142 | cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. | ||
| 143 | return error; | ||
| 144 | } | ||
| 145 | cmd_buff[1] = 0; // No error | ||
| 146 | return MakeResult<bool>(false); | ||
| 147 | } | ||
| 148 | }; | ||
| 149 | |||
| 150 | class Directory : public Kernel::Session { | ||
| 151 | public: | ||
| 152 | Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path) | ||
| 153 | : backend(std::move(backend)), path(path) { | ||
| 154 | } | ||
| 155 | |||
| 156 | std::string GetName() const override { return "Directory: " + path.DebugStr(); } | ||
| 157 | |||
| 158 | FileSys::Path path; ///< Path of the directory | ||
| 159 | std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface | ||
| 160 | |||
| 161 | ResultVal<bool> SyncRequest() override { | ||
| 162 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 163 | DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); | ||
| 164 | switch (cmd) { | ||
| 165 | |||
| 166 | // Read from directory... | ||
| 167 | case DirectoryCommand::Read: | ||
| 168 | { | ||
| 169 | u32 count = cmd_buff[1]; | ||
| 170 | u32 address = cmd_buff[3]; | ||
| 171 | auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); | ||
| 172 | LOG_TRACE(Service_FS, "Read %s %s: count=%d", | ||
| 173 | GetTypeName().c_str(), GetName().c_str(), count); | ||
| 174 | |||
| 175 | // Number of entries actually read | ||
| 176 | cmd_buff[2] = backend->Read(count, entries); | ||
| 177 | break; | ||
| 178 | } | ||
| 179 | |||
| 180 | case DirectoryCommand::Close: | ||
| 181 | { | ||
| 182 | LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); | ||
| 183 | Kernel::g_object_pool.Destroy<Directory>(GetHandle()); | ||
| 184 | break; | ||
| 185 | } | ||
| 186 | |||
| 187 | // Unknown command... | ||
| 188 | default: | ||
| 189 | LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); | ||
| 190 | ResultCode error = UnimplementedFunction(ErrorModule::FS); | ||
| 191 | cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. | ||
| 192 | return MakeResult<bool>(false); | ||
| 193 | } | ||
| 194 | cmd_buff[1] = 0; // No error | ||
| 195 | return MakeResult<bool>(false); | ||
| 196 | } | ||
| 197 | }; | ||
| 198 | |||
| 199 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 200 | |||
| 201 | /** | ||
| 202 | * Map of registered archives, identified by id code. Once an archive is registered here, it is | ||
| 203 | * never removed until the FS service is shut down. | ||
| 204 | */ | ||
| 205 | static std::unordered_map<ArchiveIdCode, std::unique_ptr<Archive>> id_code_map; | ||
| 206 | |||
| 207 | /** | ||
| 208 | * Map of active archive handles. Values are pointers to the archives in `idcode_map`. | ||
| 209 | */ | ||
| 210 | static std::unordered_map<ArchiveHandle, Archive*> handle_map; | ||
| 211 | static ArchiveHandle next_handle; | ||
| 212 | |||
| 213 | static Archive* GetArchive(ArchiveHandle handle) { | ||
| 214 | auto itr = handle_map.find(handle); | ||
| 215 | return (itr == handle_map.end()) ? nullptr : itr->second; | ||
| 216 | } | ||
| 217 | |||
| 218 | ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code) { | ||
| 219 | LOG_TRACE(Service_FS, "Opening archive with id code 0x%08X", id_code); | ||
| 220 | |||
| 221 | auto itr = id_code_map.find(id_code); | ||
| 222 | if (itr == id_code_map.end()) { | ||
| 223 | // TODO: Verify error against hardware | ||
| 224 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | ||
| 225 | ErrorSummary::NotFound, ErrorLevel::Permanent); | ||
| 226 | } | ||
| 227 | |||
| 228 | // This should never even happen in the first place with 64-bit handles, | ||
| 229 | while (handle_map.count(next_handle) != 0) { | ||
| 230 | ++next_handle; | ||
| 231 | } | ||
| 232 | handle_map.emplace(next_handle, itr->second.get()); | ||
| 233 | return MakeResult<ArchiveHandle>(next_handle++); | ||
| 234 | } | ||
| 235 | |||
| 236 | ResultCode CloseArchive(ArchiveHandle handle) { | ||
| 237 | if (handle_map.erase(handle) == 0) | ||
| 238 | return InvalidHandle(ErrorModule::FS); | ||
| 239 | else | ||
| 240 | return RESULT_SUCCESS; | ||
| 241 | } | ||
| 242 | |||
| 243 | // TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in | ||
| 244 | // http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22 | ||
| 245 | ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) { | ||
| 246 | auto result = id_code_map.emplace(id_code, std::make_unique<Archive>(std::move(backend), id_code)); | ||
| 247 | |||
| 248 | bool inserted = result.second; | ||
| 249 | _dbg_assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code"); | ||
| 250 | |||
| 251 | auto& archive = result.first->second; | ||
| 252 | LOG_DEBUG(Service_FS, "Registered archive %s with id code 0x%08X", archive->GetName().c_str(), id_code); | ||
| 253 | return RESULT_SUCCESS; | ||
| 254 | } | ||
| 255 | |||
| 256 | ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { | ||
| 257 | Archive* archive = GetArchive(archive_handle); | ||
| 258 | if (archive == nullptr) | ||
| 259 | return InvalidHandle(ErrorModule::FS); | ||
| 260 | |||
| 261 | std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode); | ||
| 262 | if (backend == nullptr) { | ||
| 263 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | ||
| 264 | ErrorSummary::NotFound, ErrorLevel::Permanent); | ||
| 265 | } | ||
| 266 | |||
| 267 | auto file = std::make_unique<File>(std::move(backend), path); | ||
| 268 | Handle handle = Kernel::g_object_pool.Create(file.release()); | ||
| 269 | return MakeResult<Handle>(handle); | ||
| 270 | } | ||
| 271 | |||
| 272 | ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ||
| 273 | Archive* archive = GetArchive(archive_handle); | ||
| 274 | if (archive == nullptr) | ||
| 275 | return InvalidHandle(ErrorModule::FS); | ||
| 276 | |||
| 277 | if (archive->backend->DeleteFile(path)) | ||
| 278 | return RESULT_SUCCESS; | ||
| 279 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description | ||
| 280 | ErrorSummary::Canceled, ErrorLevel::Status); | ||
| 281 | } | ||
| 282 | |||
| 283 | ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, | ||
| 284 | ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { | ||
| 285 | Archive* src_archive = GetArchive(src_archive_handle); | ||
| 286 | Archive* dest_archive = GetArchive(dest_archive_handle); | ||
| 287 | if (src_archive == nullptr || dest_archive == nullptr) | ||
| 288 | return InvalidHandle(ErrorModule::FS); | ||
| 289 | |||
| 290 | if (src_archive == dest_archive) { | ||
| 291 | if (src_archive->backend->RenameFile(src_path, dest_path)) | ||
| 292 | return RESULT_SUCCESS; | ||
| 293 | } else { | ||
| 294 | // TODO: Implement renaming across archives | ||
| 295 | return UnimplementedFunction(ErrorModule::FS); | ||
| 296 | } | ||
| 297 | |||
| 298 | // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't | ||
| 299 | // exist or similar. Verify. | ||
| 300 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description | ||
| 301 | ErrorSummary::NothingHappened, ErrorLevel::Status); | ||
| 302 | } | ||
| 303 | |||
| 304 | ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ||
| 305 | Archive* archive = GetArchive(archive_handle); | ||
| 306 | if (archive == nullptr) | ||
| 307 | return InvalidHandle(ErrorModule::FS); | ||
| 308 | |||
| 309 | if (archive->backend->DeleteDirectory(path)) | ||
| 310 | return RESULT_SUCCESS; | ||
| 311 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description | ||
| 312 | ErrorSummary::Canceled, ErrorLevel::Status); | ||
| 313 | } | ||
| 314 | |||
| 315 | ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ||
| 316 | Archive* archive = GetArchive(archive_handle); | ||
| 317 | if (archive == nullptr) | ||
| 318 | return InvalidHandle(ErrorModule::FS); | ||
| 319 | |||
| 320 | if (archive->backend->CreateDirectory(path)) | ||
| 321 | return RESULT_SUCCESS; | ||
| 322 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description | ||
| 323 | ErrorSummary::Canceled, ErrorLevel::Status); | ||
| 324 | } | ||
| 325 | |||
| 326 | ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, | ||
| 327 | ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { | ||
| 328 | Archive* src_archive = GetArchive(src_archive_handle); | ||
| 329 | Archive* dest_archive = GetArchive(dest_archive_handle); | ||
| 330 | if (src_archive == nullptr || dest_archive == nullptr) | ||
| 331 | return InvalidHandle(ErrorModule::FS); | ||
| 332 | |||
| 333 | if (src_archive == dest_archive) { | ||
| 334 | if (src_archive->backend->RenameDirectory(src_path, dest_path)) | ||
| 335 | return RESULT_SUCCESS; | ||
| 336 | } else { | ||
| 337 | // TODO: Implement renaming across archives | ||
| 338 | return UnimplementedFunction(ErrorModule::FS); | ||
| 339 | } | ||
| 340 | |||
| 341 | // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't | ||
| 342 | // exist or similar. Verify. | ||
| 343 | return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description | ||
| 344 | ErrorSummary::NothingHappened, ErrorLevel::Status); | ||
| 345 | } | ||
| 346 | |||
| 347 | /** | ||
| 348 | * Open a Directory from an Archive | ||
| 349 | * @param archive_handle Handle to an open Archive object | ||
| 350 | * @param path Path to the Directory inside of the Archive | ||
| 351 | * @return Opened Directory object | ||
| 352 | */ | ||
| 353 | ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ||
| 354 | Archive* archive = GetArchive(archive_handle); | ||
| 355 | if (archive == nullptr) | ||
| 356 | return InvalidHandle(ErrorModule::FS); | ||
| 357 | |||
| 358 | std::unique_ptr<FileSys::DirectoryBackend> backend = archive->backend->OpenDirectory(path); | ||
| 359 | if (backend == nullptr) { | ||
| 360 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | ||
| 361 | ErrorSummary::NotFound, ErrorLevel::Permanent); | ||
| 362 | } | ||
| 363 | |||
| 364 | auto directory = std::make_unique<Directory>(std::move(backend), path); | ||
| 365 | Handle handle = Kernel::g_object_pool.Create(directory.release()); | ||
| 366 | return MakeResult<Handle>(handle); | ||
| 367 | } | ||
| 368 | |||
| 369 | /// Initialize archives | ||
| 370 | void ArchiveInit() { | ||
| 371 | next_handle = 1; | ||
| 372 | |||
| 373 | // TODO(Link Mauve): Add the other archive types (see here for the known types: | ||
| 374 | // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished | ||
| 375 | // archive type is SDMC, so it is the only one getting exposed. | ||
| 376 | |||
| 377 | std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); | ||
| 378 | auto archive = std::make_unique<FileSys::Archive_SDMC>(sdmc_directory); | ||
| 379 | if (archive->Initialize()) | ||
| 380 | CreateArchive(std::move(archive), ArchiveIdCode::SDMC); | ||
| 381 | else | ||
| 382 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); | ||
| 383 | } | ||
| 384 | |||
| 385 | /// Shutdown archives | ||
| 386 | void ArchiveShutdown() { | ||
| 387 | handle_map.clear(); | ||
| 388 | id_code_map.clear(); | ||
| 389 | } | ||
| 390 | |||
| 391 | } // namespace FS | ||
| 392 | } // namespace Service | ||
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h new file mode 100644 index 000000000..a38de92e3 --- /dev/null +++ b/src/core/hle/service/fs/archive.h | |||
| @@ -0,0 +1,119 @@ | |||
| 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/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/result.h" | ||
| 12 | |||
| 13 | namespace Service { | ||
| 14 | namespace FS { | ||
| 15 | |||
| 16 | /// Supported archive types | ||
| 17 | enum class ArchiveIdCode : u32 { | ||
| 18 | RomFS = 0x00000003, | ||
| 19 | SaveData = 0x00000004, | ||
| 20 | ExtSaveData = 0x00000006, | ||
| 21 | SharedExtSaveData = 0x00000007, | ||
| 22 | SystemSaveData = 0x00000008, | ||
| 23 | SDMC = 0x00000009, | ||
| 24 | SDMCWriteOnly = 0x0000000A, | ||
| 25 | }; | ||
| 26 | |||
| 27 | typedef u64 ArchiveHandle; | ||
| 28 | |||
| 29 | /** | ||
| 30 | * Opens an archive | ||
| 31 | * @param id_code IdCode of the archive to open | ||
| 32 | * @return Handle to the opened archive | ||
| 33 | */ | ||
| 34 | ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code); | ||
| 35 | |||
| 36 | /** | ||
| 37 | * Closes an archive | ||
| 38 | * @param id_code IdCode of the archive to open | ||
| 39 | */ | ||
| 40 | ResultCode CloseArchive(ArchiveHandle handle); | ||
| 41 | |||
| 42 | /** | ||
| 43 | * Creates an Archive | ||
| 44 | * @param backend File system backend interface to the archive | ||
| 45 | * @param id_code Id code used to access this type of archive | ||
| 46 | */ | ||
| 47 | ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code); | ||
| 48 | |||
| 49 | /** | ||
| 50 | * Open a File from an Archive | ||
| 51 | * @param archive_handle Handle to an open Archive object | ||
| 52 | * @param path Path to the File inside of the Archive | ||
| 53 | * @param mode Mode under which to open the File | ||
| 54 | * @return Handle to the opened File object | ||
| 55 | */ | ||
| 56 | ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); | ||
| 57 | |||
| 58 | /** | ||
| 59 | * Delete a File from an Archive | ||
| 60 | * @param archive_handle Handle to an open Archive object | ||
| 61 | * @param path Path to the File inside of the Archive | ||
| 62 | * @return Whether deletion succeeded | ||
| 63 | */ | ||
| 64 | ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Rename a File between two Archives | ||
| 68 | * @param src_archive_handle Handle to the source Archive object | ||
| 69 | * @param src_path Path to the File inside of the source Archive | ||
| 70 | * @param dest_archive_handle Handle to the destination Archive object | ||
| 71 | * @param dest_path Path to the File inside of the destination Archive | ||
| 72 | * @return Whether rename succeeded | ||
| 73 | */ | ||
| 74 | ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, | ||
| 75 | ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path); | ||
| 76 | |||
| 77 | /** | ||
| 78 | * Delete a Directory from an Archive | ||
| 79 | * @param archive_handle Handle to an open Archive object | ||
| 80 | * @param path Path to the Directory inside of the Archive | ||
| 81 | * @return Whether deletion succeeded | ||
| 82 | */ | ||
| 83 | ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); | ||
| 84 | |||
| 85 | /** | ||
| 86 | * Create a Directory from an Archive | ||
| 87 | * @param archive_handle Handle to an open Archive object | ||
| 88 | * @param path Path to the Directory inside of the Archive | ||
| 89 | * @return Whether creation of directory succeeded | ||
| 90 | */ | ||
| 91 | ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); | ||
| 92 | |||
| 93 | /** | ||
| 94 | * Rename a Directory between two Archives | ||
| 95 | * @param src_archive_handle Handle to the source Archive object | ||
| 96 | * @param src_path Path to the Directory inside of the source Archive | ||
| 97 | * @param dest_archive_handle Handle to the destination Archive object | ||
| 98 | * @param dest_path Path to the Directory inside of the destination Archive | ||
| 99 | * @return Whether rename succeeded | ||
| 100 | */ | ||
| 101 | ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, | ||
| 102 | ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path); | ||
| 103 | |||
| 104 | /** | ||
| 105 | * Open a Directory from an Archive | ||
| 106 | * @param archive_handle Handle to an open Archive object | ||
| 107 | * @param path Path to the Directory inside of the Archive | ||
| 108 | * @return Handle to the opened File object | ||
| 109 | */ | ||
| 110 | ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); | ||
| 111 | |||
| 112 | /// Initialize archives | ||
| 113 | void ArchiveInit(); | ||
| 114 | |||
| 115 | /// Shutdown archives | ||
| 116 | void ArchiveShutdown(); | ||
| 117 | |||
| 118 | } // namespace FS | ||
| 119 | } // namespace Service | ||
diff --git a/src/core/hle/service/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 672ba2475..0f75d5e3a 100644 --- a/src/core/hle/service/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp | |||
| @@ -3,18 +3,23 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/common.h" | 5 | #include "common/common.h" |
| 6 | #include "common/scope_exit.h" | ||
| 6 | 7 | ||
| 7 | #include "common/string_util.h" | 8 | #include "common/string_util.h" |
| 8 | #include "core/hle/kernel/archive.h" | 9 | #include "core/hle/service/fs/archive.h" |
| 9 | #include "core/hle/kernel/archive.h" | ||
| 10 | #include "core/hle/result.h" | 10 | #include "core/hle/result.h" |
| 11 | #include "core/hle/service/fs_user.h" | 11 | #include "core/hle/service/fs/fs_user.h" |
| 12 | #include "core/settings.h" | 12 | #include "core/settings.h" |
| 13 | 13 | ||
| 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 15 | // Namespace FS_User | 15 | // Namespace FS_User |
| 16 | 16 | ||
| 17 | namespace FS_User { | 17 | namespace Service { |
| 18 | namespace FS { | ||
| 19 | |||
| 20 | static ArchiveHandle MakeArchiveHandle(u32 low_word, u32 high_word) { | ||
| 21 | return (u64)low_word | ((u64)high_word << 32); | ||
| 22 | } | ||
| 18 | 23 | ||
| 19 | static void Initialize(Service::Interface* self) { | 24 | static void Initialize(Service::Interface* self) { |
| 20 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 25 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| @@ -57,11 +62,12 @@ static void OpenFile(Service::Interface* self) { | |||
| 57 | 62 | ||
| 58 | LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); | 63 | LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); |
| 59 | 64 | ||
| 60 | ResultVal<Handle> handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode); | 65 | ResultVal<Handle> handle = OpenFileFromArchive(archive_handle, file_path, mode); |
| 61 | cmd_buff[1] = handle.Code().raw; | 66 | cmd_buff[1] = handle.Code().raw; |
| 62 | if (handle.Succeeded()) { | 67 | if (handle.Succeeded()) { |
| 63 | cmd_buff[3] = *handle; | 68 | cmd_buff[3] = *handle; |
| 64 | } else { | 69 | } else { |
| 70 | cmd_buff[3] = 0; | ||
| 65 | LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); | 71 | LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); |
| 66 | } | 72 | } |
| 67 | } | 73 | } |
| @@ -88,7 +94,7 @@ static void OpenFile(Service::Interface* self) { | |||
| 88 | static void OpenFileDirectly(Service::Interface* self) { | 94 | static void OpenFileDirectly(Service::Interface* self) { |
| 89 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 95 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 90 | 96 | ||
| 91 | auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]); | 97 | auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[2]); |
| 92 | auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[3]); | 98 | auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[3]); |
| 93 | u32 archivename_size = cmd_buff[4]; | 99 | u32 archivename_size = cmd_buff[4]; |
| 94 | auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[5]); | 100 | auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[5]); |
| @@ -106,25 +112,25 @@ static void OpenFileDirectly(Service::Interface* self) { | |||
| 106 | if (archive_path.GetType() != FileSys::Empty) { | 112 | if (archive_path.GetType() != FileSys::Empty) { |
| 107 | LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); | 113 | LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); |
| 108 | cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; | 114 | cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; |
| 115 | cmd_buff[3] = 0; | ||
| 109 | return; | 116 | return; |
| 110 | } | 117 | } |
| 111 | 118 | ||
| 112 | // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it | 119 | ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id); |
| 113 | // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here? | ||
| 114 | ResultVal<Handle> archive_handle = Kernel::OpenArchive(archive_id); | ||
| 115 | cmd_buff[1] = archive_handle.Code().raw; | ||
| 116 | if (archive_handle.Failed()) { | 120 | if (archive_handle.Failed()) { |
| 117 | LOG_ERROR(Service_FS, "failed to get a handle for archive"); | 121 | LOG_ERROR(Service_FS, "failed to get a handle for archive"); |
| 122 | cmd_buff[1] = archive_handle.Code().raw; | ||
| 123 | cmd_buff[3] = 0; | ||
| 118 | return; | 124 | return; |
| 119 | } | 125 | } |
| 120 | // cmd_buff[2] isn't used according to 3dmoo's implementation. | 126 | SCOPE_EXIT({ CloseArchive(*archive_handle); }); |
| 121 | cmd_buff[3] = *archive_handle; | ||
| 122 | 127 | ||
| 123 | ResultVal<Handle> handle = Kernel::OpenFileFromArchive(*archive_handle, file_path, mode); | 128 | ResultVal<Handle> handle = OpenFileFromArchive(*archive_handle, file_path, mode); |
| 124 | cmd_buff[1] = handle.Code().raw; | 129 | cmd_buff[1] = handle.Code().raw; |
| 125 | if (handle.Succeeded()) { | 130 | if (handle.Succeeded()) { |
| 126 | cmd_buff[3] = *handle; | 131 | cmd_buff[3] = *handle; |
| 127 | } else { | 132 | } else { |
| 133 | cmd_buff[3] = 0; | ||
| 128 | LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); | 134 | LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); |
| 129 | } | 135 | } |
| 130 | } | 136 | } |
| @@ -140,12 +146,10 @@ static void OpenFileDirectly(Service::Interface* self) { | |||
| 140 | * Outputs: | 146 | * Outputs: |
| 141 | * 1 : Result of function, 0 on success, otherwise error code | 147 | * 1 : Result of function, 0 on success, otherwise error code |
| 142 | */ | 148 | */ |
| 143 | void DeleteFile(Service::Interface* self) { | 149 | static void DeleteFile(Service::Interface* self) { |
| 144 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 150 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 145 | 151 | ||
| 146 | // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to | 152 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); |
| 147 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 148 | Handle archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 149 | auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | 153 | auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); |
| 150 | u32 filename_size = cmd_buff[5]; | 154 | u32 filename_size = cmd_buff[5]; |
| 151 | u32 filename_ptr = cmd_buff[7]; | 155 | u32 filename_ptr = cmd_buff[7]; |
| @@ -155,7 +159,7 @@ void DeleteFile(Service::Interface* self) { | |||
| 155 | LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", | 159 | LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", |
| 156 | filename_type, filename_size, file_path.DebugStr().c_str()); | 160 | filename_type, filename_size, file_path.DebugStr().c_str()); |
| 157 | 161 | ||
| 158 | cmd_buff[1] = Kernel::DeleteFileFromArchive(archive_handle, file_path).raw; | 162 | cmd_buff[1] = DeleteFileFromArchive(archive_handle, file_path).raw; |
| 159 | } | 163 | } |
| 160 | 164 | ||
| 161 | /* | 165 | /* |
| @@ -174,15 +178,13 @@ void DeleteFile(Service::Interface* self) { | |||
| 174 | * Outputs: | 178 | * Outputs: |
| 175 | * 1 : Result of function, 0 on success, otherwise error code | 179 | * 1 : Result of function, 0 on success, otherwise error code |
| 176 | */ | 180 | */ |
| 177 | void RenameFile(Service::Interface* self) { | 181 | static void RenameFile(Service::Interface* self) { |
| 178 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 182 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 179 | 183 | ||
| 180 | // TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to | 184 | ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); |
| 181 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 182 | Handle src_archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 183 | auto src_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | 185 | auto src_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); |
| 184 | u32 src_filename_size = cmd_buff[5]; | 186 | u32 src_filename_size = cmd_buff[5]; |
| 185 | Handle dest_archive_handle = static_cast<Handle>(cmd_buff[7]); | 187 | ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]);; |
| 186 | auto dest_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[8]); | 188 | auto dest_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[8]); |
| 187 | u32 dest_filename_size = cmd_buff[9]; | 189 | u32 dest_filename_size = cmd_buff[9]; |
| 188 | u32 src_filename_ptr = cmd_buff[11]; | 190 | u32 src_filename_ptr = cmd_buff[11]; |
| @@ -195,7 +197,7 @@ void RenameFile(Service::Interface* self) { | |||
| 195 | src_filename_type, src_filename_size, src_file_path.DebugStr().c_str(), | 197 | src_filename_type, src_filename_size, src_file_path.DebugStr().c_str(), |
| 196 | dest_filename_type, dest_filename_size, dest_file_path.DebugStr().c_str()); | 198 | dest_filename_type, dest_filename_size, dest_file_path.DebugStr().c_str()); |
| 197 | 199 | ||
| 198 | cmd_buff[1] = Kernel::RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle, dest_file_path).raw; | 200 | cmd_buff[1] = RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle, dest_file_path).raw; |
| 199 | } | 201 | } |
| 200 | 202 | ||
| 201 | /* | 203 | /* |
| @@ -209,12 +211,10 @@ void RenameFile(Service::Interface* self) { | |||
| 209 | * Outputs: | 211 | * Outputs: |
| 210 | * 1 : Result of function, 0 on success, otherwise error code | 212 | * 1 : Result of function, 0 on success, otherwise error code |
| 211 | */ | 213 | */ |
| 212 | void DeleteDirectory(Service::Interface* self) { | 214 | static void DeleteDirectory(Service::Interface* self) { |
| 213 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 215 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 214 | 216 | ||
| 215 | // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to | 217 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); |
| 216 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 217 | Handle archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 218 | auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | 218 | auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); |
| 219 | u32 dirname_size = cmd_buff[5]; | 219 | u32 dirname_size = cmd_buff[5]; |
| 220 | u32 dirname_ptr = cmd_buff[7]; | 220 | u32 dirname_ptr = cmd_buff[7]; |
| @@ -224,7 +224,7 @@ void DeleteDirectory(Service::Interface* self) { | |||
| 224 | LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", | 224 | LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", |
| 225 | dirname_type, dirname_size, dir_path.DebugStr().c_str()); | 225 | dirname_type, dirname_size, dir_path.DebugStr().c_str()); |
| 226 | 226 | ||
| 227 | cmd_buff[1] = Kernel::DeleteDirectoryFromArchive(archive_handle, dir_path).raw; | 227 | cmd_buff[1] = DeleteDirectoryFromArchive(archive_handle, dir_path).raw; |
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | /* | 230 | /* |
| @@ -241,9 +241,7 @@ void DeleteDirectory(Service::Interface* self) { | |||
| 241 | static void CreateDirectory(Service::Interface* self) { | 241 | static void CreateDirectory(Service::Interface* self) { |
| 242 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 242 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 243 | 243 | ||
| 244 | // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to | 244 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); |
| 245 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 246 | Handle archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 247 | auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | 245 | auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); |
| 248 | u32 dirname_size = cmd_buff[5]; | 246 | u32 dirname_size = cmd_buff[5]; |
| 249 | u32 dirname_ptr = cmd_buff[8]; | 247 | u32 dirname_ptr = cmd_buff[8]; |
| @@ -252,7 +250,7 @@ static void CreateDirectory(Service::Interface* self) { | |||
| 252 | 250 | ||
| 253 | LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); | 251 | LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); |
| 254 | 252 | ||
| 255 | cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_path).raw; | 253 | cmd_buff[1] = CreateDirectoryFromArchive(archive_handle, dir_path).raw; |
| 256 | } | 254 | } |
| 257 | 255 | ||
| 258 | /* | 256 | /* |
| @@ -271,15 +269,13 @@ static void CreateDirectory(Service::Interface* self) { | |||
| 271 | * Outputs: | 269 | * Outputs: |
| 272 | * 1 : Result of function, 0 on success, otherwise error code | 270 | * 1 : Result of function, 0 on success, otherwise error code |
| 273 | */ | 271 | */ |
| 274 | void RenameDirectory(Service::Interface* self) { | 272 | static void RenameDirectory(Service::Interface* self) { |
| 275 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 273 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 276 | 274 | ||
| 277 | // TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to | 275 | ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); |
| 278 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 279 | Handle src_archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 280 | auto src_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); | 276 | auto src_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); |
| 281 | u32 src_dirname_size = cmd_buff[5]; | 277 | u32 src_dirname_size = cmd_buff[5]; |
| 282 | Handle dest_archive_handle = static_cast<Handle>(cmd_buff[7]); | 278 | ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]); |
| 283 | auto dest_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[8]); | 279 | auto dest_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[8]); |
| 284 | u32 dest_dirname_size = cmd_buff[9]; | 280 | u32 dest_dirname_size = cmd_buff[9]; |
| 285 | u32 src_dirname_ptr = cmd_buff[11]; | 281 | u32 src_dirname_ptr = cmd_buff[11]; |
| @@ -292,15 +288,26 @@ void RenameDirectory(Service::Interface* self) { | |||
| 292 | src_dirname_type, src_dirname_size, src_dir_path.DebugStr().c_str(), | 288 | src_dirname_type, src_dirname_size, src_dir_path.DebugStr().c_str(), |
| 293 | dest_dirname_type, dest_dirname_size, dest_dir_path.DebugStr().c_str()); | 289 | dest_dirname_type, dest_dirname_size, dest_dir_path.DebugStr().c_str()); |
| 294 | 290 | ||
| 295 | cmd_buff[1] = Kernel::RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw; | 291 | cmd_buff[1] = RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw; |
| 296 | } | 292 | } |
| 297 | 293 | ||
| 294 | /** | ||
| 295 | * FS_User::OpenDirectory service function | ||
| 296 | * Inputs: | ||
| 297 | * 1 : Archive handle low word | ||
| 298 | * 2 : Archive handle high word | ||
| 299 | * 3 : Low path type | ||
| 300 | * 4 : Low path size | ||
| 301 | * 7 : (LowPathSize << 14) | 2 | ||
| 302 | * 8 : Low path data pointer | ||
| 303 | * Outputs: | ||
| 304 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 305 | * 3 : Directory handle | ||
| 306 | */ | ||
| 298 | static void OpenDirectory(Service::Interface* self) { | 307 | static void OpenDirectory(Service::Interface* self) { |
| 299 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 308 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 300 | 309 | ||
| 301 | // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to | 310 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]); |
| 302 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 303 | Handle archive_handle = static_cast<Handle>(cmd_buff[2]); | ||
| 304 | auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]); | 311 | auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]); |
| 305 | u32 dirname_size = cmd_buff[4]; | 312 | u32 dirname_size = cmd_buff[4]; |
| 306 | u32 dirname_ptr = cmd_buff[6]; | 313 | u32 dirname_ptr = cmd_buff[6]; |
| @@ -309,7 +316,7 @@ static void OpenDirectory(Service::Interface* self) { | |||
| 309 | 316 | ||
| 310 | LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); | 317 | LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); |
| 311 | 318 | ||
| 312 | ResultVal<Handle> handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path); | 319 | ResultVal<Handle> handle = OpenDirectoryFromArchive(archive_handle, dir_path); |
| 313 | cmd_buff[1] = handle.Code().raw; | 320 | cmd_buff[1] = handle.Code().raw; |
| 314 | if (handle.Succeeded()) { | 321 | if (handle.Succeeded()) { |
| 315 | cmd_buff[3] = *handle; | 322 | cmd_buff[3] = *handle; |
| @@ -334,7 +341,7 @@ static void OpenDirectory(Service::Interface* self) { | |||
| 334 | static void OpenArchive(Service::Interface* self) { | 341 | static void OpenArchive(Service::Interface* self) { |
| 335 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 342 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 336 | 343 | ||
| 337 | auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]); | 344 | auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]); |
| 338 | auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); | 345 | auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); |
| 339 | u32 archivename_size = cmd_buff[3]; | 346 | u32 archivename_size = cmd_buff[3]; |
| 340 | u32 archivename_ptr = cmd_buff[5]; | 347 | u32 archivename_ptr = cmd_buff[5]; |
| @@ -348,16 +355,34 @@ static void OpenArchive(Service::Interface* self) { | |||
| 348 | return; | 355 | return; |
| 349 | } | 356 | } |
| 350 | 357 | ||
| 351 | ResultVal<Handle> handle = Kernel::OpenArchive(archive_id); | 358 | ResultVal<ArchiveHandle> handle = OpenArchive(archive_id); |
| 352 | cmd_buff[1] = handle.Code().raw; | 359 | cmd_buff[1] = handle.Code().raw; |
| 353 | if (handle.Succeeded()) { | 360 | if (handle.Succeeded()) { |
| 354 | // cmd_buff[2] isn't used according to 3dmoo's implementation. | 361 | cmd_buff[2] = *handle & 0xFFFFFFFF; |
| 355 | cmd_buff[3] = *handle; | 362 | cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF; |
| 356 | } else { | 363 | } else { |
| 364 | cmd_buff[2] = cmd_buff[3] = 0; | ||
| 357 | LOG_ERROR(Service_FS, "failed to get a handle for archive"); | 365 | LOG_ERROR(Service_FS, "failed to get a handle for archive"); |
| 358 | } | 366 | } |
| 359 | } | 367 | } |
| 360 | 368 | ||
| 369 | /** | ||
| 370 | * FS_User::CloseArchive service function | ||
| 371 | * Inputs: | ||
| 372 | * 0 : 0x080E0080 | ||
| 373 | * 1 : Archive handle low word | ||
| 374 | * 2 : Archive handle high word | ||
| 375 | * Outputs: | ||
| 376 | * 0 : ??? TODO(yuriks): Verify return header | ||
| 377 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 378 | */ | ||
| 379 | static void CloseArchive(Service::Interface* self) { | ||
| 380 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 381 | |||
| 382 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]); | ||
| 383 | cmd_buff[1] = CloseArchive(archive_handle).raw; | ||
| 384 | } | ||
| 385 | |||
| 361 | /* | 386 | /* |
| 362 | * FS_User::IsSdmcDetected service function | 387 | * FS_User::IsSdmcDetected service function |
| 363 | * Outputs: | 388 | * Outputs: |
| @@ -373,7 +398,7 @@ static void IsSdmcDetected(Service::Interface* self) { | |||
| 373 | LOG_DEBUG(Service_FS, "called"); | 398 | LOG_DEBUG(Service_FS, "called"); |
| 374 | } | 399 | } |
| 375 | 400 | ||
| 376 | const Interface::FunctionInfo FunctionTable[] = { | 401 | const FSUserInterface::FunctionInfo FunctionTable[] = { |
| 377 | {0x000100C6, nullptr, "Dummy1"}, | 402 | {0x000100C6, nullptr, "Dummy1"}, |
| 378 | {0x040100C4, nullptr, "Control"}, | 403 | {0x040100C4, nullptr, "Control"}, |
| 379 | {0x08010002, Initialize, "Initialize"}, | 404 | {0x08010002, Initialize, "Initialize"}, |
| @@ -389,7 +414,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 389 | {0x080B0102, OpenDirectory, "OpenDirectory"}, | 414 | {0x080B0102, OpenDirectory, "OpenDirectory"}, |
| 390 | {0x080C00C2, OpenArchive, "OpenArchive"}, | 415 | {0x080C00C2, OpenArchive, "OpenArchive"}, |
| 391 | {0x080D0144, nullptr, "ControlArchive"}, | 416 | {0x080D0144, nullptr, "ControlArchive"}, |
| 392 | {0x080E0080, nullptr, "CloseArchive"}, | 417 | {0x080E0080, CloseArchive, "CloseArchive"}, |
| 393 | {0x080F0180, nullptr, "FormatThisUserSaveData"}, | 418 | {0x080F0180, nullptr, "FormatThisUserSaveData"}, |
| 394 | {0x08100200, nullptr, "CreateSystemSaveData"}, | 419 | {0x08100200, nullptr, "CreateSystemSaveData"}, |
| 395 | {0x08110040, nullptr, "DeleteSystemSaveData"}, | 420 | {0x08110040, nullptr, "DeleteSystemSaveData"}, |
| @@ -465,11 +490,12 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 465 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 490 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 466 | // Interface class | 491 | // Interface class |
| 467 | 492 | ||
| 468 | Interface::Interface() { | 493 | FSUserInterface::FSUserInterface() { |
| 469 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | 494 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |
| 470 | } | 495 | } |
| 471 | 496 | ||
| 472 | Interface::~Interface() { | 497 | FSUserInterface::~FSUserInterface() { |
| 473 | } | 498 | } |
| 474 | 499 | ||
| 475 | } // namespace | 500 | } // namespace FS |
| 501 | } // namespace Service | ||
diff --git a/src/core/hle/service/fs_user.h b/src/core/hle/service/fs/fs_user.h index 005382540..80e3804e0 100644 --- a/src/core/hle/service/fs_user.h +++ b/src/core/hle/service/fs/fs_user.h | |||
| @@ -9,15 +9,16 @@ | |||
| 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 10 | // Namespace FS_User | 10 | // Namespace FS_User |
| 11 | 11 | ||
| 12 | namespace FS_User { | 12 | namespace Service { |
| 13 | namespace FS { | ||
| 13 | 14 | ||
| 14 | /// Interface to "fs:USER" service | 15 | /// Interface to "fs:USER" service |
| 15 | class Interface : public Service::Interface { | 16 | class FSUserInterface : public Service::Interface { |
| 16 | public: | 17 | public: |
| 17 | 18 | ||
| 18 | Interface(); | 19 | FSUserInterface(); |
| 19 | 20 | ||
| 20 | ~Interface(); | 21 | ~FSUserInterface(); |
| 21 | 22 | ||
| 22 | /** | 23 | /** |
| 23 | * Gets the string port name used by CTROS for the service | 24 | * Gets the string port name used by CTROS for the service |
| @@ -28,4 +29,5 @@ public: | |||
| 28 | } | 29 | } |
| 29 | }; | 30 | }; |
| 30 | 31 | ||
| 31 | } // namespace | 32 | } // namespace FS |
| 33 | } // namespace Service | ||
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index b33172932..2230045e3 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -17,7 +17,7 @@ | |||
| 17 | #include "core/hle/service/csnd_snd.h" | 17 | #include "core/hle/service/csnd_snd.h" |
| 18 | #include "core/hle/service/dsp_dsp.h" | 18 | #include "core/hle/service/dsp_dsp.h" |
| 19 | #include "core/hle/service/err_f.h" | 19 | #include "core/hle/service/err_f.h" |
| 20 | #include "core/hle/service/fs_user.h" | 20 | #include "core/hle/service/fs/fs_user.h" |
| 21 | #include "core/hle/service/frd_u.h" | 21 | #include "core/hle/service/frd_u.h" |
| 22 | #include "core/hle/service/gsp_gpu.h" | 22 | #include "core/hle/service/gsp_gpu.h" |
| 23 | #include "core/hle/service/hid_user.h" | 23 | #include "core/hle/service/hid_user.h" |
| @@ -99,7 +99,7 @@ void Init() { | |||
| 99 | g_manager->AddService(new DSP_DSP::Interface); | 99 | g_manager->AddService(new DSP_DSP::Interface); |
| 100 | g_manager->AddService(new ERR_F::Interface); | 100 | g_manager->AddService(new ERR_F::Interface); |
| 101 | g_manager->AddService(new FRD_U::Interface); | 101 | g_manager->AddService(new FRD_U::Interface); |
| 102 | g_manager->AddService(new FS_User::Interface); | 102 | g_manager->AddService(new FS::FSUserInterface); |
| 103 | g_manager->AddService(new GSP_GPU::Interface); | 103 | g_manager->AddService(new GSP_GPU::Interface); |
| 104 | g_manager->AddService(new HID_User::Interface); | 104 | g_manager->AddService(new HID_User::Interface); |
| 105 | g_manager->AddService(new IR_RST::Interface); | 105 | g_manager->AddService(new IR_RST::Interface); |