diff options
| author | 2014-09-18 22:27:06 -0400 | |
|---|---|---|
| committer | 2014-09-18 22:27:06 -0400 | |
| commit | a9630a9d2b432bea7bdfef4aa462035b98b34517 (patch) | |
| tree | 258010943e989fc61a2a439ff15ead7ed3d11a6f /src/core/hle/kernel/archive.cpp | |
| parent | Merge pull request #107 from lioncash/sprintf (diff) | |
| parent | Kernel: Implement the Close command for Archive, File and Directory. (diff) | |
| download | yuzu-a9630a9d2b432bea7bdfef4aa462035b98b34517.tar.gz yuzu-a9630a9d2b432bea7bdfef4aa462035b98b34517.tar.xz yuzu-a9630a9d2b432bea7bdfef4aa462035b98b34517.zip | |
Merge pull request #70 from linkmauve/master
Implement filesystem services, and the required kernel objects.
Diffstat (limited to 'src/core/hle/kernel/archive.cpp')
| -rw-r--r-- | src/core/hle/kernel/archive.cpp | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp index 20536f40f..a7fa661d6 100644 --- a/src/core/hle/kernel/archive.cpp +++ b/src/core/hle/kernel/archive.cpp | |||
| @@ -3,9 +3,12 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/common_types.h" | 5 | #include "common/common_types.h" |
| 6 | #include "common/file_util.h" | ||
| 6 | #include "common/math_util.h" | 7 | #include "common/math_util.h" |
| 7 | 8 | ||
| 8 | #include "core/file_sys/archive.h" | 9 | #include "core/file_sys/archive.h" |
| 10 | #include "core/file_sys/archive_sdmc.h" | ||
| 11 | #include "core/file_sys/directory.h" | ||
| 9 | #include "core/hle/service/service.h" | 12 | #include "core/hle/service/service.h" |
| 10 | #include "core/hle/kernel/archive.h" | 13 | #include "core/hle/kernel/archive.h" |
| 11 | 14 | ||
| @@ -29,6 +32,14 @@ enum class FileCommand : u32 { | |||
| 29 | Flush = 0x08090000, | 32 | Flush = 0x08090000, |
| 30 | }; | 33 | }; |
| 31 | 34 | ||
| 35 | // Command to access directory | ||
| 36 | enum class DirectoryCommand : u32 { | ||
| 37 | Dummy1 = 0x000100C6, | ||
| 38 | Control = 0x040100C4, | ||
| 39 | Read = 0x08010042, | ||
| 40 | Close = 0x08020000, | ||
| 41 | }; | ||
| 42 | |||
| 32 | class Archive : public Object { | 43 | class Archive : public Object { |
| 33 | public: | 44 | public: |
| 34 | std::string GetTypeName() const { return "Archive"; } | 45 | std::string GetTypeName() const { return "Archive"; } |
| @@ -85,6 +96,13 @@ public: | |||
| 85 | backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32)); | 96 | backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32)); |
| 86 | break; | 97 | break; |
| 87 | } | 98 | } |
| 99 | case FileCommand::Close: | ||
| 100 | { | ||
| 101 | DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); | ||
| 102 | Kernel::g_object_pool.Destroy<Archive>(GetHandle()); | ||
| 103 | CloseArchive(backend->GetIdCode()); | ||
| 104 | break; | ||
| 105 | } | ||
| 88 | // Unknown command... | 106 | // Unknown command... |
| 89 | default: | 107 | default: |
| 90 | { | 108 | { |
| @@ -108,6 +126,153 @@ public: | |||
| 108 | } | 126 | } |
| 109 | }; | 127 | }; |
| 110 | 128 | ||
| 129 | class File : public Object { | ||
| 130 | public: | ||
| 131 | std::string GetTypeName() const { return "File"; } | ||
| 132 | std::string GetName() const { return path; } | ||
| 133 | |||
| 134 | static Kernel::HandleType GetStaticHandleType() { return HandleType::File; } | ||
| 135 | Kernel::HandleType GetHandleType() const { return HandleType::File; } | ||
| 136 | |||
| 137 | std::string path; ///< Path of the file | ||
| 138 | std::unique_ptr<FileSys::File> backend; ///< File backend interface | ||
| 139 | |||
| 140 | /** | ||
| 141 | * Synchronize kernel object | ||
| 142 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 143 | * @return Result of operation, 0 on success, otherwise error code | ||
| 144 | */ | ||
| 145 | Result SyncRequest(bool* wait) { | ||
| 146 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 147 | FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); | ||
| 148 | switch (cmd) { | ||
| 149 | |||
| 150 | // Read from file... | ||
| 151 | case FileCommand::Read: | ||
| 152 | { | ||
| 153 | u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; | ||
| 154 | u32 length = cmd_buff[3]; | ||
| 155 | u32 address = cmd_buff[5]; | ||
| 156 | DEBUG_LOG(KERNEL, "Read %s %s: offset=0x%x length=%d address=0x%x", | ||
| 157 | GetTypeName().c_str(), GetName().c_str(), offset, length, address); | ||
| 158 | cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); | ||
| 159 | break; | ||
| 160 | } | ||
| 161 | |||
| 162 | // Write to file... | ||
| 163 | case FileCommand::Write: | ||
| 164 | { | ||
| 165 | u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; | ||
| 166 | u32 length = cmd_buff[3]; | ||
| 167 | u32 flush = cmd_buff[4]; | ||
| 168 | u32 address = cmd_buff[6]; | ||
| 169 | DEBUG_LOG(KERNEL, "Write %s %s: offset=0x%x length=%d address=0x%x, flush=0x%x", | ||
| 170 | GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); | ||
| 171 | cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); | ||
| 172 | break; | ||
| 173 | } | ||
| 174 | |||
| 175 | case FileCommand::GetSize: | ||
| 176 | { | ||
| 177 | DEBUG_LOG(KERNEL, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str()); | ||
| 178 | u64 size = backend->GetSize(); | ||
| 179 | cmd_buff[2] = (u32)size; | ||
| 180 | cmd_buff[3] = size >> 32; | ||
| 181 | break; | ||
| 182 | } | ||
| 183 | |||
| 184 | case FileCommand::Close: | ||
| 185 | { | ||
| 186 | DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); | ||
| 187 | Kernel::g_object_pool.Destroy<File>(GetHandle()); | ||
| 188 | break; | ||
| 189 | } | ||
| 190 | |||
| 191 | // Unknown command... | ||
| 192 | default: | ||
| 193 | ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); | ||
| 194 | cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. | ||
| 195 | return -1; | ||
| 196 | } | ||
| 197 | cmd_buff[1] = 0; // No error | ||
| 198 | return 0; | ||
| 199 | } | ||
| 200 | |||
| 201 | /** | ||
| 202 | * Wait for kernel object to synchronize | ||
| 203 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 204 | * @return Result of operation, 0 on success, otherwise error code | ||
| 205 | */ | ||
| 206 | Result WaitSynchronization(bool* wait) { | ||
| 207 | // TODO(bunnei): ImplementMe | ||
| 208 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | ||
| 209 | return 0; | ||
| 210 | } | ||
| 211 | }; | ||
| 212 | |||
| 213 | class Directory : public Object { | ||
| 214 | public: | ||
| 215 | std::string GetTypeName() const { return "Directory"; } | ||
| 216 | std::string GetName() const { return path; } | ||
| 217 | |||
| 218 | static Kernel::HandleType GetStaticHandleType() { return HandleType::Directory; } | ||
| 219 | Kernel::HandleType GetHandleType() const { return HandleType::Directory; } | ||
| 220 | |||
| 221 | std::string path; ///< Path of the directory | ||
| 222 | std::unique_ptr<FileSys::Directory> backend; ///< File backend interface | ||
| 223 | |||
| 224 | /** | ||
| 225 | * Synchronize kernel object | ||
| 226 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 227 | * @return Result of operation, 0 on success, otherwise error code | ||
| 228 | */ | ||
| 229 | Result SyncRequest(bool* wait) { | ||
| 230 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 231 | DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); | ||
| 232 | switch (cmd) { | ||
| 233 | |||
| 234 | // Read from directory... | ||
| 235 | case DirectoryCommand::Read: | ||
| 236 | { | ||
| 237 | u32 count = cmd_buff[1]; | ||
| 238 | u32 address = cmd_buff[3]; | ||
| 239 | FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); | ||
| 240 | DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count); | ||
| 241 | |||
| 242 | // Number of entries actually read | ||
| 243 | cmd_buff[2] = backend->Read(count, entries); | ||
| 244 | break; | ||
| 245 | } | ||
| 246 | |||
| 247 | case DirectoryCommand::Close: | ||
| 248 | { | ||
| 249 | DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); | ||
| 250 | Kernel::g_object_pool.Destroy<Directory>(GetHandle()); | ||
| 251 | break; | ||
| 252 | } | ||
| 253 | |||
| 254 | // Unknown command... | ||
| 255 | default: | ||
| 256 | ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); | ||
| 257 | cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. | ||
| 258 | return -1; | ||
| 259 | } | ||
| 260 | cmd_buff[1] = 0; // No error | ||
| 261 | return 0; | ||
| 262 | } | ||
| 263 | |||
| 264 | /** | ||
| 265 | * Wait for kernel object to synchronize | ||
| 266 | * @param wait Boolean wait set if current thread should wait as a result of sync operation | ||
| 267 | * @return Result of operation, 0 on success, otherwise error code | ||
| 268 | */ | ||
| 269 | Result WaitSynchronization(bool* wait) { | ||
| 270 | // TODO(bunnei): ImplementMe | ||
| 271 | ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | ||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | }; | ||
| 275 | |||
| 111 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 276 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 112 | 277 | ||
| 113 | std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode | 278 | std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode |
| @@ -126,6 +291,21 @@ Handle OpenArchive(FileSys::Archive::IdCode id_code) { | |||
| 126 | } | 291 | } |
| 127 | 292 | ||
| 128 | /** | 293 | /** |
| 294 | * Closes an archive | ||
| 295 | * @param id_code IdCode of the archive to open | ||
| 296 | * @return Result of operation, 0 on success, otherwise error code | ||
| 297 | */ | ||
| 298 | Result CloseArchive(FileSys::Archive::IdCode id_code) { | ||
| 299 | if (1 != g_archive_map.erase(id_code)) { | ||
| 300 | ERROR_LOG(KERNEL, "Cannot close archive %d", (int) id_code); | ||
| 301 | return -1; | ||
| 302 | } | ||
| 303 | |||
| 304 | INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); | ||
| 305 | return 0; | ||
| 306 | } | ||
| 307 | |||
| 308 | /** | ||
| 129 | * Mounts an archive | 309 | * Mounts an archive |
| 130 | * @param archive Pointer to the archive to mount | 310 | * @param archive Pointer to the archive to mount |
| 131 | * @return Result of operation, 0 on success, otherwise error code | 311 | * @return Result of operation, 0 on success, otherwise error code |
| @@ -171,9 +351,56 @@ Handle CreateArchive(FileSys::Archive* backend, const std::string& name) { | |||
| 171 | return handle; | 351 | return handle; |
| 172 | } | 352 | } |
| 173 | 353 | ||
| 354 | /** | ||
| 355 | * Open a File from an Archive | ||
| 356 | * @param archive_handle Handle to an open Archive object | ||
| 357 | * @param path Path to the File inside of the Archive | ||
| 358 | * @param mode Mode under which to open the File | ||
| 359 | * @return Opened File object | ||
| 360 | */ | ||
| 361 | Handle OpenFileFromArchive(Handle archive_handle, const std::string& path, const FileSys::Mode mode) { | ||
| 362 | File* file = new File; | ||
| 363 | Handle handle = Kernel::g_object_pool.Create(file); | ||
| 364 | |||
| 365 | Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); | ||
| 366 | file->path = path; | ||
| 367 | file->backend = archive->backend->OpenFile(path, mode); | ||
| 368 | |||
| 369 | return handle; | ||
| 370 | } | ||
| 371 | |||
| 372 | /** | ||
| 373 | * Open a Directory from an Archive | ||
| 374 | * @param archive_handle Handle to an open Archive object | ||
| 375 | * @param path Path to the Directory inside of the Archive | ||
| 376 | * @return Opened Directory object | ||
| 377 | */ | ||
| 378 | Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& path) { | ||
| 379 | Directory* directory = new Directory; | ||
| 380 | Handle handle = Kernel::g_object_pool.Create(directory); | ||
| 381 | |||
| 382 | Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); | ||
| 383 | directory->path = path; | ||
| 384 | directory->backend = archive->backend->OpenDirectory(path); | ||
| 385 | |||
| 386 | return handle; | ||
| 387 | } | ||
| 388 | |||
| 174 | /// Initialize archives | 389 | /// Initialize archives |
| 175 | void ArchiveInit() { | 390 | void ArchiveInit() { |
| 176 | g_archive_map.clear(); | 391 | g_archive_map.clear(); |
| 392 | |||
| 393 | // TODO(Link Mauve): Add the other archive types (see here for the known types: | ||
| 394 | // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished | ||
| 395 | // archive type is SDMC, so it is the only one getting exposed. | ||
| 396 | |||
| 397 | // TODO(Link Mauve): don't assume the path separator is '/'. | ||
| 398 | std::string sdmc_directory = FileUtil::GetCurrentDir() + "/userdata/sdmc"; | ||
| 399 | auto archive = new FileSys::Archive_SDMC(sdmc_directory); | ||
| 400 | if (archive->Initialize()) | ||
| 401 | CreateArchive(archive, "SDMC"); | ||
| 402 | else | ||
| 403 | ERROR_LOG(KERNEL, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); | ||
| 177 | } | 404 | } |
| 178 | 405 | ||
| 179 | /// Shutdown archives | 406 | /// Shutdown archives |