diff options
Diffstat (limited to 'src/core/hle/kernel/archive.cpp')
| -rw-r--r-- | src/core/hle/kernel/archive.cpp | 147 |
1 files changed, 65 insertions, 82 deletions
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp index 900f484c7..e11dddc84 100644 --- a/src/core/hle/kernel/archive.cpp +++ b/src/core/hle/kernel/archive.cpp | |||
| @@ -9,8 +9,9 @@ | |||
| 9 | #include "core/file_sys/archive.h" | 9 | #include "core/file_sys/archive.h" |
| 10 | #include "core/file_sys/archive_sdmc.h" | 10 | #include "core/file_sys/archive_sdmc.h" |
| 11 | #include "core/file_sys/directory.h" | 11 | #include "core/file_sys/directory.h" |
| 12 | #include "core/hle/service/service.h" | ||
| 13 | #include "core/hle/kernel/archive.h" | 12 | #include "core/hle/kernel/archive.h" |
| 13 | #include "core/hle/result.h" | ||
| 14 | #include "core/hle/service/service.h" | ||
| 14 | 15 | ||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 16 | // Kernel namespace | 17 | // Kernel namespace |
| @@ -56,7 +57,7 @@ public: | |||
| 56 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 57 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 57 | * @return Result of operation, 0 on success, otherwise error code | 58 | * @return Result of operation, 0 on success, otherwise error code |
| 58 | */ | 59 | */ |
| 59 | Result SyncRequest(bool* wait) override { | 60 | ResultVal<bool> SyncRequest() override { |
| 60 | u32* cmd_buff = Service::GetCommandBuffer(); | 61 | u32* cmd_buff = Service::GetCommandBuffer(); |
| 61 | FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); | 62 | FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); |
| 62 | 63 | ||
| @@ -106,11 +107,11 @@ public: | |||
| 106 | default: | 107 | default: |
| 107 | { | 108 | { |
| 108 | ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); | 109 | ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); |
| 109 | return -1; | 110 | return UnimplementedFunction(ErrorModule::FS); |
| 110 | } | 111 | } |
| 111 | } | 112 | } |
| 112 | cmd_buff[1] = 0; // No error | 113 | cmd_buff[1] = 0; // No error |
| 113 | return 0; | 114 | return MakeResult<bool>(false); |
| 114 | } | 115 | } |
| 115 | 116 | ||
| 116 | /** | 117 | /** |
| @@ -118,10 +119,10 @@ public: | |||
| 118 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 119 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 119 | * @return Result of operation, 0 on success, otherwise error code | 120 | * @return Result of operation, 0 on success, otherwise error code |
| 120 | */ | 121 | */ |
| 121 | Result WaitSynchronization(bool* wait) override { | 122 | ResultVal<bool> WaitSynchronization() override { |
| 122 | // TODO(bunnei): ImplementMe | 123 | // TODO(bunnei): ImplementMe |
| 123 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | 124 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); |
| 124 | return 0; | 125 | return UnimplementedFunction(ErrorModule::FS); |
| 125 | } | 126 | } |
| 126 | }; | 127 | }; |
| 127 | 128 | ||
| @@ -141,7 +142,7 @@ public: | |||
| 141 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 142 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 142 | * @return Result of operation, 0 on success, otherwise error code | 143 | * @return Result of operation, 0 on success, otherwise error code |
| 143 | */ | 144 | */ |
| 144 | Result SyncRequest(bool* wait) override { | 145 | ResultVal<bool> SyncRequest() override { |
| 145 | u32* cmd_buff = Service::GetCommandBuffer(); | 146 | u32* cmd_buff = Service::GetCommandBuffer(); |
| 146 | FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); | 147 | FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); |
| 147 | switch (cmd) { | 148 | switch (cmd) { |
| @@ -183,7 +184,8 @@ public: | |||
| 183 | case FileCommand::SetSize: | 184 | case FileCommand::SetSize: |
| 184 | { | 185 | { |
| 185 | u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); | 186 | u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); |
| 186 | DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size); | 187 | DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", |
| 188 | GetTypeName().c_str(), GetName().c_str(), size); | ||
| 187 | backend->SetSize(size); | 189 | backend->SetSize(size); |
| 188 | break; | 190 | break; |
| 189 | } | 191 | } |
| @@ -198,11 +200,12 @@ public: | |||
| 198 | // Unknown command... | 200 | // Unknown command... |
| 199 | default: | 201 | default: |
| 200 | ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); | 202 | ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); |
| 201 | cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. | 203 | ResultCode error = UnimplementedFunction(ErrorModule::FS); |
| 202 | return -1; | 204 | cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. |
| 205 | return error; | ||
| 203 | } | 206 | } |
| 204 | cmd_buff[1] = 0; // No error | 207 | cmd_buff[1] = 0; // No error |
| 205 | return 0; | 208 | return MakeResult<bool>(false); |
| 206 | } | 209 | } |
| 207 | 210 | ||
| 208 | /** | 211 | /** |
| @@ -210,10 +213,10 @@ public: | |||
| 210 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 213 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 211 | * @return Result of operation, 0 on success, otherwise error code | 214 | * @return Result of operation, 0 on success, otherwise error code |
| 212 | */ | 215 | */ |
| 213 | Result WaitSynchronization(bool* wait) override { | 216 | ResultVal<bool> WaitSynchronization() override { |
| 214 | // TODO(bunnei): ImplementMe | 217 | // TODO(bunnei): ImplementMe |
| 215 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | 218 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); |
| 216 | return 0; | 219 | return UnimplementedFunction(ErrorModule::FS); |
| 217 | } | 220 | } |
| 218 | }; | 221 | }; |
| 219 | 222 | ||
| @@ -233,7 +236,7 @@ public: | |||
| 233 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 236 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 234 | * @return Result of operation, 0 on success, otherwise error code | 237 | * @return Result of operation, 0 on success, otherwise error code |
| 235 | */ | 238 | */ |
| 236 | Result SyncRequest(bool* wait) override { | 239 | ResultVal<bool> SyncRequest() override { |
| 237 | u32* cmd_buff = Service::GetCommandBuffer(); | 240 | u32* cmd_buff = Service::GetCommandBuffer(); |
| 238 | DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); | 241 | DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); |
| 239 | switch (cmd) { | 242 | switch (cmd) { |
| @@ -243,8 +246,9 @@ public: | |||
| 243 | { | 246 | { |
| 244 | u32 count = cmd_buff[1]; | 247 | u32 count = cmd_buff[1]; |
| 245 | u32 address = cmd_buff[3]; | 248 | u32 address = cmd_buff[3]; |
| 246 | FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); | 249 | auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); |
| 247 | DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count); | 250 | DEBUG_LOG(KERNEL, "Read %s %s: count=%d", |
| 251 | GetTypeName().c_str(), GetName().c_str(), count); | ||
| 248 | 252 | ||
| 249 | // Number of entries actually read | 253 | // Number of entries actually read |
| 250 | cmd_buff[2] = backend->Read(count, entries); | 254 | cmd_buff[2] = backend->Read(count, entries); |
| @@ -261,11 +265,12 @@ public: | |||
| 261 | // Unknown command... | 265 | // Unknown command... |
| 262 | default: | 266 | default: |
| 263 | ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); | 267 | ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); |
| 264 | cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. | 268 | ResultCode error = UnimplementedFunction(ErrorModule::FS); |
| 265 | return -1; | 269 | cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. |
| 270 | return error; | ||
| 266 | } | 271 | } |
| 267 | cmd_buff[1] = 0; // No error | 272 | cmd_buff[1] = 0; // No error |
| 268 | return 0; | 273 | return MakeResult<bool>(false); |
| 269 | } | 274 | } |
| 270 | 275 | ||
| 271 | /** | 276 | /** |
| @@ -273,10 +278,10 @@ public: | |||
| 273 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | 278 | * @param wait Boolean wait set if current thread should wait as a result of sync operation |
| 274 | * @return Result of operation, 0 on success, otherwise error code | 279 | * @return Result of operation, 0 on success, otherwise error code |
| 275 | */ | 280 | */ |
| 276 | Result WaitSynchronization(bool* wait) override { | 281 | ResultVal<bool> WaitSynchronization() override { |
| 277 | // TODO(bunnei): ImplementMe | 282 | // TODO(bunnei): ImplementMe |
| 278 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | 283 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); |
| 279 | return 0; | 284 | return UnimplementedFunction(ErrorModule::FS); |
| 280 | } | 285 | } |
| 281 | }; | 286 | }; |
| 282 | 287 | ||
| @@ -284,89 +289,59 @@ public: | |||
| 284 | 289 | ||
| 285 | std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode | 290 | std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode |
| 286 | 291 | ||
| 287 | /** | 292 | ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code) { |
| 288 | * Opens an archive | ||
| 289 | * @param id_code IdCode of the archive to open | ||
| 290 | * @return Handle to archive if it exists, otherwise a null handle (0) | ||
| 291 | */ | ||
| 292 | Handle OpenArchive(FileSys::Archive::IdCode id_code) { | ||
| 293 | auto itr = g_archive_map.find(id_code); | 293 | auto itr = g_archive_map.find(id_code); |
| 294 | if (itr == g_archive_map.end()) { | 294 | if (itr == g_archive_map.end()) { |
| 295 | return 0; | 295 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, |
| 296 | ErrorSummary::NotFound, ErrorLevel::Permanent); | ||
| 296 | } | 297 | } |
| 297 | return itr->second; | 298 | |
| 299 | return MakeResult<Handle>(itr->second); | ||
| 298 | } | 300 | } |
| 299 | 301 | ||
| 300 | /** | 302 | ResultCode CloseArchive(FileSys::Archive::IdCode id_code) { |
| 301 | * Closes an archive | ||
| 302 | * @param id_code IdCode of the archive to open | ||
| 303 | * @return Result of operation, 0 on success, otherwise error code | ||
| 304 | */ | ||
| 305 | Result CloseArchive(FileSys::Archive::IdCode id_code) { | ||
| 306 | auto itr = g_archive_map.find(id_code); | 303 | auto itr = g_archive_map.find(id_code); |
| 307 | if (itr == g_archive_map.end()) { | 304 | if (itr == g_archive_map.end()) { |
| 308 | ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code); | 305 | ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code); |
| 309 | return -1; | 306 | return InvalidHandle(ErrorModule::FS); |
| 310 | } | 307 | } |
| 311 | 308 | ||
| 312 | INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); | 309 | INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); |
| 313 | return 0; | 310 | return RESULT_SUCCESS; |
| 314 | } | 311 | } |
| 315 | 312 | ||
| 316 | /** | 313 | /** |
| 317 | * Mounts an archive | 314 | * Mounts an archive |
| 318 | * @param archive Pointer to the archive to mount | 315 | * @param archive Pointer to the archive to mount |
| 319 | * @return Result of operation, 0 on success, otherwise error code | 316 | * @return Result of operation |
| 320 | */ | 317 | */ |
| 321 | Result MountArchive(Archive* archive) { | 318 | ResultCode MountArchive(Archive* archive) { |
| 322 | FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); | 319 | FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); |
| 323 | if (0 != OpenArchive(id_code)) { | 320 | ResultVal<Handle> archive_handle = OpenArchive(id_code); |
| 321 | if (archive_handle.Succeeded()) { | ||
| 324 | ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); | 322 | ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); |
| 325 | return -1; | 323 | return archive_handle.Code(); |
| 326 | } | 324 | } |
| 327 | g_archive_map[id_code] = archive->GetHandle(); | 325 | g_archive_map[id_code] = archive->GetHandle(); |
| 328 | INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str()); | 326 | INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str()); |
| 329 | return 0; | 327 | return RESULT_SUCCESS; |
| 330 | } | 328 | } |
| 331 | 329 | ||
| 332 | /** | 330 | ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) { |
| 333 | * Creates an Archive | ||
| 334 | * @param handle Handle to newly created archive object | ||
| 335 | * @param backend File system backend interface to the archive | ||
| 336 | * @param name Optional name of Archive | ||
| 337 | * @return Newly created Archive object | ||
| 338 | */ | ||
| 339 | Archive* CreateArchive(Handle& handle, FileSys::Archive* backend, const std::string& name) { | ||
| 340 | Archive* archive = new Archive; | 331 | Archive* archive = new Archive; |
| 341 | handle = Kernel::g_object_pool.Create(archive); | 332 | Handle handle = Kernel::g_object_pool.Create(archive); |
| 342 | archive->name = name; | 333 | archive->name = name; |
| 343 | archive->backend = backend; | 334 | archive->backend = backend; |
| 344 | 335 | ||
| 345 | MountArchive(archive); | 336 | ResultCode result = MountArchive(archive); |
| 346 | 337 | if (result.IsError()) { | |
| 347 | return archive; | 338 | return result; |
| 348 | } | 339 | } |
| 349 | 340 | ||
| 350 | /** | 341 | return RESULT_SUCCESS; |
| 351 | * Creates an Archive | ||
| 352 | * @param backend File system backend interface to the archive | ||
| 353 | * @param name Optional name of Archive | ||
| 354 | * @return Handle to newly created Archive object | ||
| 355 | */ | ||
| 356 | Handle CreateArchive(FileSys::Archive* backend, const std::string& name) { | ||
| 357 | Handle handle; | ||
| 358 | CreateArchive(handle, backend, name); | ||
| 359 | return handle; | ||
| 360 | } | 342 | } |
| 361 | 343 | ||
| 362 | /** | 344 | ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { |
| 363 | * Open a File from an Archive | ||
| 364 | * @param archive_handle Handle to an open Archive object | ||
| 365 | * @param path Path to the File inside of the Archive | ||
| 366 | * @param mode Mode under which to open the File | ||
| 367 | * @return Opened File object | ||
| 368 | */ | ||
| 369 | Handle OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { | ||
| 370 | // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create | 345 | // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create |
| 371 | // the archive file handles at app loading, and then keep them persistent throughout execution. | 346 | // the archive file handles at app loading, and then keep them persistent throughout execution. |
| 372 | // Archives file handles are just reused and not actually freed until emulation shut down. | 347 | // Archives file handles are just reused and not actually freed until emulation shut down. |
| @@ -376,19 +351,24 @@ Handle OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, con | |||
| 376 | // design. While the functionally of this is OK, our implementation decision to separate | 351 | // design. While the functionally of this is OK, our implementation decision to separate |
| 377 | // normal files from archive file pointers is very likely wrong. | 352 | // normal files from archive file pointers is very likely wrong. |
| 378 | // See https://github.com/citra-emu/citra/issues/205 | 353 | // See https://github.com/citra-emu/citra/issues/205 |
| 379 | return archive_handle; | 354 | return MakeResult<Handle>(archive_handle); |
| 380 | 355 | ||
| 381 | File* file = new File; | 356 | File* file = new File; |
| 382 | Handle handle = Kernel::g_object_pool.Create(file); | 357 | Handle handle = Kernel::g_object_pool.Create(file); |
| 383 | 358 | ||
| 384 | Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); | 359 | Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle); |
| 360 | if (archive == nullptr) { | ||
| 361 | return InvalidHandle(ErrorModule::FS); | ||
| 362 | } | ||
| 385 | file->path = path; | 363 | file->path = path; |
| 386 | file->backend = archive->backend->OpenFile(path, mode); | 364 | file->backend = archive->backend->OpenFile(path, mode); |
| 387 | 365 | ||
| 388 | if (!file->backend) | 366 | if (!file->backend) { |
| 389 | return 0; | 367 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, |
| 368 | ErrorSummary::NotFound, ErrorLevel::Permanent); | ||
| 369 | } | ||
| 390 | 370 | ||
| 391 | return handle; | 371 | return MakeResult<Handle>(handle); |
| 392 | } | 372 | } |
| 393 | 373 | ||
| 394 | /** | 374 | /** |
| @@ -442,15 +422,18 @@ Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& pa | |||
| 442 | * @param path Path to the Directory inside of the Archive | 422 | * @param path Path to the Directory inside of the Archive |
| 443 | * @return Opened Directory object | 423 | * @return Opened Directory object |
| 444 | */ | 424 | */ |
| 445 | Handle OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { | 425 | ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { |
| 446 | Directory* directory = new Directory; | 426 | Directory* directory = new Directory; |
| 447 | Handle handle = Kernel::g_object_pool.Create(directory); | 427 | Handle handle = Kernel::g_object_pool.Create(directory); |
| 448 | 428 | ||
| 449 | Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); | 429 | Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle); |
| 430 | if (archive == nullptr) { | ||
| 431 | return InvalidHandle(ErrorModule::FS); | ||
| 432 | } | ||
| 450 | directory->path = path; | 433 | directory->path = path; |
| 451 | directory->backend = archive->backend->OpenDirectory(path); | 434 | directory->backend = archive->backend->OpenDirectory(path); |
| 452 | 435 | ||
| 453 | return handle; | 436 | return MakeResult<Handle>(handle); |
| 454 | } | 437 | } |
| 455 | 438 | ||
| 456 | /// Initialize archives | 439 | /// Initialize archives |