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 | |
| 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')
| -rw-r--r-- | src/core/hle/kernel/archive.cpp | 227 | ||||
| -rw-r--r-- | src/core/hle/kernel/archive.h | 24 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 1 | ||||
| -rw-r--r-- | src/core/hle/service/fs.cpp | 197 |
4 files changed, 429 insertions, 20 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 |
diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/kernel/archive.h index 3758e7061..593861f8e 100644 --- a/src/core/hle/kernel/archive.h +++ b/src/core/hle/kernel/archive.h | |||
| @@ -22,6 +22,13 @@ namespace Kernel { | |||
| 22 | Handle OpenArchive(FileSys::Archive::IdCode id_code); | 22 | Handle OpenArchive(FileSys::Archive::IdCode id_code); |
| 23 | 23 | ||
| 24 | /** | 24 | /** |
| 25 | * Closes an archive | ||
| 26 | * @param id_code IdCode of the archive to open | ||
| 27 | * @return true if it worked fine | ||
| 28 | */ | ||
| 29 | Result CloseArchive(FileSys::Archive::IdCode id_code); | ||
| 30 | |||
| 31 | /** | ||
| 25 | * Creates an Archive | 32 | * Creates an Archive |
| 26 | * @param backend File system backend interface to the archive | 33 | * @param backend File system backend interface to the archive |
| 27 | * @param name Optional name of Archive | 34 | * @param name Optional name of Archive |
| @@ -29,6 +36,23 @@ Handle OpenArchive(FileSys::Archive::IdCode id_code); | |||
| 29 | */ | 36 | */ |
| 30 | Handle CreateArchive(FileSys::Archive* backend, const std::string& name); | 37 | Handle CreateArchive(FileSys::Archive* backend, const std::string& name); |
| 31 | 38 | ||
| 39 | /** | ||
| 40 | * Open a File from an Archive | ||
| 41 | * @param archive_handle Handle to an open Archive object | ||
| 42 | * @param path Path to the File inside of the Archive | ||
| 43 | * @param mode Mode under which to open the File | ||
| 44 | * @return Opened File object | ||
| 45 | */ | ||
| 46 | Handle OpenFileFromArchive(Handle handle, const std::string& name, const FileSys::Mode mode); | ||
| 47 | |||
| 48 | /** | ||
| 49 | * Open a Directory from an Archive | ||
| 50 | * @param archive_handle Handle to an open Archive object | ||
| 51 | * @param path Path to the Directory inside of the Archive | ||
| 52 | * @return Opened Directory object | ||
| 53 | */ | ||
| 54 | Handle OpenDirectoryFromArchive(Handle handle, const std::string& name); | ||
| 55 | |||
| 32 | /// Initialize archives | 56 | /// Initialize archives |
| 33 | void ArchiveInit(); | 57 | void ArchiveInit(); |
| 34 | 58 | ||
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 0e7e5ff68..867d1b89c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -32,6 +32,7 @@ enum class HandleType : u32 { | |||
| 32 | File = 10, | 32 | File = 10, |
| 33 | Semaphore = 11, | 33 | Semaphore = 11, |
| 34 | Archive = 12, | 34 | Archive = 12, |
| 35 | Directory = 13, | ||
| 35 | }; | 36 | }; |
| 36 | 37 | ||
| 37 | enum { | 38 | enum { |
diff --git a/src/core/hle/service/fs.cpp b/src/core/hle/service/fs.cpp index 9e1998b0f..8469d9840 100644 --- a/src/core/hle/service/fs.cpp +++ b/src/core/hle/service/fs.cpp | |||
| @@ -12,35 +12,192 @@ | |||
| 12 | 12 | ||
| 13 | namespace FS_User { | 13 | namespace FS_User { |
| 14 | 14 | ||
| 15 | // Command to access archive file | ||
| 16 | enum class LowPathType : u32 { | ||
| 17 | Invalid = 0, | ||
| 18 | Empty = 1, | ||
| 19 | Binary = 2, | ||
| 20 | Char = 3, | ||
| 21 | Wchar = 4 | ||
| 22 | }; | ||
| 23 | |||
| 24 | std::string GetStringFromCmdBuff(const u32 pointer, const u32 size) { | ||
| 25 | auto data = reinterpret_cast<const char*>(Memory::GetPointer(pointer)); | ||
| 26 | return std::string(data, size - 1); | ||
| 27 | } | ||
| 28 | |||
| 29 | // We currently return 0 for success and -1 for failure in cmd_buff[1]. -1 was chosen because it | ||
| 30 | // puts all the sections of the http://3dbrew.org/wiki/Error_codes to something non-zero, to make | ||
| 31 | // sure we don't mislead the application into thinking something worked. | ||
| 32 | |||
| 15 | void Initialize(Service::Interface* self) { | 33 | void Initialize(Service::Interface* self) { |
| 16 | u32* cmd_buff = Service::GetCommandBuffer(); | 34 | u32* cmd_buff = Service::GetCommandBuffer(); |
| 17 | cmd_buff[1] = 0; // No error | 35 | |
| 36 | // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per | ||
| 37 | // http://3dbrew.org/wiki/FS:Initialize#Request | ||
| 38 | cmd_buff[1] = 0; | ||
| 39 | |||
| 40 | DEBUG_LOG(KERNEL, "called"); | ||
| 41 | } | ||
| 42 | |||
| 43 | void OpenFile(Service::Interface* self) { | ||
| 44 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 45 | |||
| 46 | u32 transaction = cmd_buff[1]; | ||
| 47 | // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to | ||
| 48 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 49 | Handle archive_handle = static_cast<Handle>(cmd_buff[3]); | ||
| 50 | LowPathType type = static_cast<LowPathType>(cmd_buff[4]); | ||
| 51 | u32 size = cmd_buff[5]; | ||
| 52 | FileSys::Mode mode; mode.hex = cmd_buff[6]; | ||
| 53 | u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes. | ||
| 54 | u32 pointer = cmd_buff[9]; | ||
| 55 | |||
| 56 | if (type != LowPathType::Char) { | ||
| 57 | ERROR_LOG(KERNEL, "file LowPath type other than char is currently unsupported"); | ||
| 58 | cmd_buff[1] = -1; | ||
| 59 | return; | ||
| 60 | } | ||
| 61 | |||
| 62 | std::string file_name = GetStringFromCmdBuff(pointer, size); | ||
| 63 | |||
| 64 | DEBUG_LOG(KERNEL, "type=%d size=%d mode=%d attrs=%d data=%s", type, size, mode, attributes, file_name.c_str()); | ||
| 65 | |||
| 66 | Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_name, mode); | ||
| 67 | if (handle) { | ||
| 68 | cmd_buff[1] = 0; | ||
| 69 | cmd_buff[3] = handle; | ||
| 70 | } else { | ||
| 71 | ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_name.c_str()); | ||
| 72 | // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. | ||
| 73 | cmd_buff[1] = -1; | ||
| 74 | } | ||
| 75 | |||
| 18 | DEBUG_LOG(KERNEL, "called"); | 76 | DEBUG_LOG(KERNEL, "called"); |
| 19 | } | 77 | } |
| 20 | 78 | ||
| 21 | void OpenFileDirectly(Service::Interface* self) { | 79 | void OpenFileDirectly(Service::Interface* self) { |
| 22 | u32* cmd_buff = Service::GetCommandBuffer(); | 80 | u32* cmd_buff = Service::GetCommandBuffer(); |
| 23 | 81 | ||
| 24 | FileSys::Archive::IdCode arch_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]); | 82 | u32 transaction = cmd_buff[1]; |
| 25 | 83 | auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]); | |
| 26 | // TODO(bunnei): Properly implement use of these... | 84 | LowPathType archive_type = static_cast<LowPathType>(cmd_buff[3]); |
| 27 | //u32 transaction = cmd_buff[1]; | 85 | u32 archive_size = cmd_buff[4]; |
| 28 | //u32 arch_lowpath_type = cmd_buff[3]; | 86 | LowPathType type = static_cast<LowPathType>(cmd_buff[5]); |
| 29 | //u32 arch_lowpath_sz = cmd_buff[4]; | 87 | u32 size = cmd_buff[6]; |
| 30 | //u32 file_lowpath_type = cmd_buff[5]; | 88 | FileSys::Mode mode; mode.hex = cmd_buff[7]; |
| 31 | //u32 file_lowpath_sz = cmd_buff[6]; | 89 | u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes. |
| 32 | //u32 flags = cmd_buff[7]; | 90 | u32 archive_pointer = cmd_buff[10]; |
| 33 | //u32 attr = cmd_buff[8]; | 91 | u32 pointer = cmd_buff[12]; |
| 34 | //u32 arch_lowpath_desc = cmd_buff[9]; | 92 | |
| 35 | //u32 arch_lowpath_ptr = cmd_buff[10]; | 93 | if (archive_type != LowPathType::Empty) { |
| 36 | //u32 file_lowpath_desc = cmd_buff[11]; | 94 | ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); |
| 37 | //u32 file_lowpath_ptr = cmd_buff[12]; | 95 | cmd_buff[1] = -1; |
| 96 | return; | ||
| 97 | } | ||
| 98 | |||
| 99 | if (type != LowPathType::Char) { | ||
| 100 | ERROR_LOG(KERNEL, "file LowPath type other than char is currently unsupported"); | ||
| 101 | cmd_buff[1] = -1; | ||
| 102 | return; | ||
| 103 | } | ||
| 104 | |||
| 105 | std::string archive_name = GetStringFromCmdBuff(archive_pointer, archive_size); | ||
| 106 | std::string file_name = GetStringFromCmdBuff(pointer, size); | ||
| 107 | |||
| 108 | DEBUG_LOG(KERNEL, "archive_type=%d archive_size=%d archive_data=%s" | ||
| 109 | "file_type=%d file_size=%d file_mode=%d file_attrs=%d file_data=%s", | ||
| 110 | archive_type, archive_size, archive_name.c_str(), | ||
| 111 | type, size, mode, attributes, file_name.c_str()); | ||
| 112 | |||
| 113 | // TODO(Link Mauve): check if we should even get a handle for the archive, and don't leak it. | ||
| 114 | Handle archive_handle = Kernel::OpenArchive(archive_id); | ||
| 115 | if (archive_handle) { | ||
| 116 | cmd_buff[1] = 0; | ||
| 117 | // cmd_buff[2] isn't used according to 3dmoo's implementation. | ||
| 118 | cmd_buff[3] = archive_handle; | ||
| 119 | } else { | ||
| 120 | ERROR_LOG(KERNEL, "failed to get a handle for archive %s", archive_name.c_str()); | ||
| 121 | // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. | ||
| 122 | cmd_buff[1] = -1; | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | |||
| 126 | Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_name, mode); | ||
| 127 | if (handle) { | ||
| 128 | cmd_buff[1] = 0; | ||
| 129 | cmd_buff[3] = handle; | ||
| 130 | } else { | ||
| 131 | ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_name.c_str()); | ||
| 132 | // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. | ||
| 133 | cmd_buff[1] = -1; | ||
| 134 | } | ||
| 135 | |||
| 136 | DEBUG_LOG(KERNEL, "called"); | ||
| 137 | } | ||
| 138 | |||
| 139 | void OpenDirectory(Service::Interface* self) { | ||
| 140 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 141 | |||
| 142 | // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to | ||
| 143 | // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. | ||
| 144 | Handle archive_handle = static_cast<Handle>(cmd_buff[2]); | ||
| 145 | LowPathType type = static_cast<LowPathType>(cmd_buff[3]); | ||
| 146 | u32 size = cmd_buff[4]; | ||
| 147 | u32 pointer = cmd_buff[6]; | ||
| 148 | |||
| 149 | if (type != LowPathType::Char) { | ||
| 150 | ERROR_LOG(KERNEL, "directory LowPath type other than char is currently unsupported"); | ||
| 151 | cmd_buff[1] = -1; | ||
| 152 | return; | ||
| 153 | } | ||
| 154 | |||
| 155 | std::string dir_name = GetStringFromCmdBuff(pointer, size); | ||
| 156 | |||
| 157 | DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", type, size, dir_name.c_str()); | ||
| 158 | |||
| 159 | Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_name); | ||
| 160 | if (handle) { | ||
| 161 | cmd_buff[1] = 0; | ||
| 162 | cmd_buff[3] = handle; | ||
| 163 | } else { | ||
| 164 | ERROR_LOG(KERNEL, "failed to get a handle for directory %s", dir_name.c_str()); | ||
| 165 | // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. | ||
| 166 | cmd_buff[1] = -1; | ||
| 167 | } | ||
| 168 | |||
| 169 | DEBUG_LOG(KERNEL, "called"); | ||
| 170 | } | ||
| 171 | |||
| 172 | void OpenArchive(Service::Interface* self) { | ||
| 173 | u32* cmd_buff = Service::GetCommandBuffer(); | ||
| 174 | |||
| 175 | auto arch_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]); | ||
| 176 | LowPathType type = static_cast<LowPathType>(cmd_buff[2]); | ||
| 177 | u32 size = cmd_buff[3]; | ||
| 178 | u32 pointer = cmd_buff[5]; | ||
| 179 | |||
| 180 | if (type != LowPathType::Empty) { | ||
| 181 | ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); | ||
| 182 | cmd_buff[1] = -1; | ||
| 183 | return; | ||
| 184 | } | ||
| 185 | |||
| 186 | std::string archive_name = GetStringFromCmdBuff(pointer, size); | ||
| 187 | |||
| 188 | DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", type, size, archive_name.c_str()); | ||
| 38 | 189 | ||
| 39 | Handle handle = Kernel::OpenArchive(arch_id); | 190 | Handle handle = Kernel::OpenArchive(arch_id); |
| 40 | if (0 != handle) { | 191 | if (handle) { |
| 41 | cmd_buff[1] = 0; // No error | 192 | cmd_buff[1] = 0; |
| 193 | // cmd_buff[2] isn't used according to 3dmoo's implementation. | ||
| 42 | cmd_buff[3] = handle; | 194 | cmd_buff[3] = handle; |
| 195 | } else { | ||
| 196 | ERROR_LOG(KERNEL, "failed to get a handle for archive %s", archive_name.c_str()); | ||
| 197 | // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. | ||
| 198 | cmd_buff[1] = -1; | ||
| 43 | } | 199 | } |
| 200 | |||
| 44 | DEBUG_LOG(KERNEL, "called"); | 201 | DEBUG_LOG(KERNEL, "called"); |
| 45 | } | 202 | } |
| 46 | 203 | ||
| @@ -48,7 +205,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 48 | {0x000100C6, nullptr, "Dummy1"}, | 205 | {0x000100C6, nullptr, "Dummy1"}, |
| 49 | {0x040100C4, nullptr, "Control"}, | 206 | {0x040100C4, nullptr, "Control"}, |
| 50 | {0x08010002, Initialize, "Initialize"}, | 207 | {0x08010002, Initialize, "Initialize"}, |
| 51 | {0x080201C2, nullptr, "OpenFile"}, | 208 | {0x080201C2, OpenFile, "OpenFile"}, |
| 52 | {0x08030204, OpenFileDirectly, "OpenFileDirectly"}, | 209 | {0x08030204, OpenFileDirectly, "OpenFileDirectly"}, |
| 53 | {0x08040142, nullptr, "DeleteFile"}, | 210 | {0x08040142, nullptr, "DeleteFile"}, |
| 54 | {0x08050244, nullptr, "RenameFile"}, | 211 | {0x08050244, nullptr, "RenameFile"}, |
| @@ -57,8 +214,8 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 57 | {0x08080202, nullptr, "CreateFile"}, | 214 | {0x08080202, nullptr, "CreateFile"}, |
| 58 | {0x08090182, nullptr, "CreateDirectory"}, | 215 | {0x08090182, nullptr, "CreateDirectory"}, |
| 59 | {0x080A0244, nullptr, "RenameDirectory"}, | 216 | {0x080A0244, nullptr, "RenameDirectory"}, |
| 60 | {0x080B0102, nullptr, "OpenDirectory"}, | 217 | {0x080B0102, OpenDirectory, "OpenDirectory"}, |
| 61 | {0x080C00C2, nullptr, "OpenArchive"}, | 218 | {0x080C00C2, OpenArchive, "OpenArchive"}, |
| 62 | {0x080D0144, nullptr, "ControlArchive"}, | 219 | {0x080D0144, nullptr, "ControlArchive"}, |
| 63 | {0x080E0080, nullptr, "CloseArchive"}, | 220 | {0x080E0080, nullptr, "CloseArchive"}, |
| 64 | {0x080F0180, nullptr, "FormatThisUserSaveData"}, | 221 | {0x080F0180, nullptr, "FormatThisUserSaveData"}, |