summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/archive.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/archive.cpp')
-rw-r--r--src/core/hle/kernel/archive.cpp429
1 files changed, 0 insertions, 429 deletions
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp
deleted file mode 100644
index e273444c9..000000000
--- a/src/core/hle/kernel/archive.cpp
+++ /dev/null
@@ -1,429 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/common_types.h"
6#include "common/file_util.h"
7#include "common/math_util.h"
8
9#include "core/file_sys/archive.h"
10#include "core/file_sys/archive_sdmc.h"
11#include "core/file_sys/directory.h"
12#include "core/hle/kernel/archive.h"
13#include "core/hle/result.h"
14#include "core/hle/service/service.h"
15
16////////////////////////////////////////////////////////////////////////////////////////////////////
17// Kernel namespace
18
19namespace Kernel {
20
21// Command to access archive file
22enum class FileCommand : u32 {
23 Dummy1 = 0x000100C6,
24 Control = 0x040100C4,
25 OpenSubFile = 0x08010100,
26 Read = 0x080200C2,
27 Write = 0x08030102,
28 GetSize = 0x08040000,
29 SetSize = 0x08050080,
30 GetAttributes = 0x08060000,
31 SetAttributes = 0x08070040,
32 Close = 0x08080000,
33 Flush = 0x08090000,
34};
35
36// Command to access directory
37enum class DirectoryCommand : u32 {
38 Dummy1 = 0x000100C6,
39 Control = 0x040100C4,
40 Read = 0x08010042,
41 Close = 0x08020000,
42};
43
44class Archive : public Object {
45public:
46 std::string GetTypeName() const override { return "Archive"; }
47 std::string GetName() const override { return name; }
48
49 static Kernel::HandleType GetStaticHandleType() { return HandleType::Archive; }
50 Kernel::HandleType GetHandleType() const override { return HandleType::Archive; }
51
52 std::string name; ///< Name of archive (optional)
53 FileSys::Archive* backend; ///< Archive backend interface
54
55 ResultVal<bool> SyncRequest() override {
56 u32* cmd_buff = Service::GetCommandBuffer();
57 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
58
59 switch (cmd) {
60 // Read from archive...
61 case FileCommand::Read:
62 {
63 u64 offset = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
64 u32 length = cmd_buff[3];
65 u32 address = cmd_buff[5];
66
67 // Number of bytes read
68 cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address));
69 break;
70 }
71 // Write to archive...
72 case FileCommand::Write:
73 {
74 u64 offset = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
75 u32 length = cmd_buff[3];
76 u32 flush = cmd_buff[4];
77 u32 address = cmd_buff[6];
78
79 // Number of bytes written
80 cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address));
81 break;
82 }
83 case FileCommand::GetSize:
84 {
85 u64 filesize = (u64) backend->GetSize();
86 cmd_buff[2] = (u32) filesize; // Lower word
87 cmd_buff[3] = (u32) (filesize >> 32); // Upper word
88 break;
89 }
90 case FileCommand::SetSize:
91 {
92 backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32));
93 break;
94 }
95 case FileCommand::Close:
96 {
97 DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
98 CloseArchive(backend->GetIdCode());
99 break;
100 }
101 // Unknown command...
102 default:
103 {
104 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
105 return UnimplementedFunction(ErrorModule::FS);
106 }
107 }
108 cmd_buff[1] = 0; // No error
109 return MakeResult<bool>(false);
110 }
111
112 ResultVal<bool> WaitSynchronization() override {
113 // TODO(bunnei): ImplementMe
114 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
115 return UnimplementedFunction(ErrorModule::FS);
116 }
117};
118
119class File : public Object {
120public:
121 std::string GetTypeName() const override { return "File"; }
122 std::string GetName() const override { return path.DebugStr(); }
123
124 static Kernel::HandleType GetStaticHandleType() { return HandleType::File; }
125 Kernel::HandleType GetHandleType() const override { return HandleType::File; }
126
127 FileSys::Path path; ///< Path of the file
128 std::unique_ptr<FileSys::File> backend; ///< File backend interface
129
130 ResultVal<bool> SyncRequest() override {
131 u32* cmd_buff = Service::GetCommandBuffer();
132 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
133 switch (cmd) {
134
135 // Read from file...
136 case FileCommand::Read:
137 {
138 u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32;
139 u32 length = cmd_buff[3];
140 u32 address = cmd_buff[5];
141 DEBUG_LOG(KERNEL, "Read %s %s: offset=0x%llx length=%d address=0x%x",
142 GetTypeName().c_str(), GetName().c_str(), offset, length, address);
143 cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address));
144 break;
145 }
146
147 // Write to file...
148 case FileCommand::Write:
149 {
150 u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32;
151 u32 length = cmd_buff[3];
152 u32 flush = cmd_buff[4];
153 u32 address = cmd_buff[6];
154 DEBUG_LOG(KERNEL, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
155 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
156 cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address));
157 break;
158 }
159
160 case FileCommand::GetSize:
161 {
162 DEBUG_LOG(KERNEL, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str());
163 u64 size = backend->GetSize();
164 cmd_buff[2] = (u32)size;
165 cmd_buff[3] = size >> 32;
166 break;
167 }
168
169 case FileCommand::SetSize:
170 {
171 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
172 DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu",
173 GetTypeName().c_str(), GetName().c_str(), size);
174 backend->SetSize(size);
175 break;
176 }
177
178 case FileCommand::Close:
179 {
180 DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
181 Kernel::g_object_pool.Destroy<File>(GetHandle());
182 break;
183 }
184
185 // Unknown command...
186 default:
187 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
188 ResultCode error = UnimplementedFunction(ErrorModule::FS);
189 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
190 return error;
191 }
192 cmd_buff[1] = 0; // No error
193 return MakeResult<bool>(false);
194 }
195
196 ResultVal<bool> WaitSynchronization() override {
197 // TODO(bunnei): ImplementMe
198 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
199 return UnimplementedFunction(ErrorModule::FS);
200 }
201};
202
203class Directory : public Object {
204public:
205 std::string GetTypeName() const override { return "Directory"; }
206 std::string GetName() const override { return path.DebugStr(); }
207
208 static Kernel::HandleType GetStaticHandleType() { return HandleType::Directory; }
209 Kernel::HandleType GetHandleType() const override { return HandleType::Directory; }
210
211 FileSys::Path path; ///< Path of the directory
212 std::unique_ptr<FileSys::Directory> backend; ///< File backend interface
213
214 ResultVal<bool> SyncRequest() override {
215 u32* cmd_buff = Service::GetCommandBuffer();
216 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
217 switch (cmd) {
218
219 // Read from directory...
220 case DirectoryCommand::Read:
221 {
222 u32 count = cmd_buff[1];
223 u32 address = cmd_buff[3];
224 auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address));
225 DEBUG_LOG(KERNEL, "Read %s %s: count=%d",
226 GetTypeName().c_str(), GetName().c_str(), count);
227
228 // Number of entries actually read
229 cmd_buff[2] = backend->Read(count, entries);
230 break;
231 }
232
233 case DirectoryCommand::Close:
234 {
235 DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
236 Kernel::g_object_pool.Destroy<Directory>(GetHandle());
237 break;
238 }
239
240 // Unknown command...
241 default:
242 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
243 ResultCode error = UnimplementedFunction(ErrorModule::FS);
244 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
245 return error;
246 }
247 cmd_buff[1] = 0; // No error
248 return MakeResult<bool>(false);
249 }
250
251 ResultVal<bool> WaitSynchronization() override {
252 // TODO(bunnei): ImplementMe
253 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
254 return UnimplementedFunction(ErrorModule::FS);
255 }
256};
257
258////////////////////////////////////////////////////////////////////////////////////////////////////
259
260std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode
261
262ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code) {
263 auto itr = g_archive_map.find(id_code);
264 if (itr == g_archive_map.end()) {
265 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
266 ErrorSummary::NotFound, ErrorLevel::Permanent);
267 }
268
269 return MakeResult<Handle>(itr->second);
270}
271
272ResultCode CloseArchive(FileSys::Archive::IdCode id_code) {
273 auto itr = g_archive_map.find(id_code);
274 if (itr == g_archive_map.end()) {
275 ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code);
276 return InvalidHandle(ErrorModule::FS);
277 }
278
279 INFO_LOG(KERNEL, "Closed archive %d", (int) id_code);
280 return RESULT_SUCCESS;
281}
282
283/**
284 * Mounts an archive
285 * @param archive Pointer to the archive to mount
286 */
287ResultCode MountArchive(Archive* archive) {
288 FileSys::Archive::IdCode id_code = archive->backend->GetIdCode();
289 ResultVal<Handle> archive_handle = OpenArchive(id_code);
290 if (archive_handle.Succeeded()) {
291 ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code);
292 return archive_handle.Code();
293 }
294 g_archive_map[id_code] = archive->GetHandle();
295 INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str());
296 return RESULT_SUCCESS;
297}
298
299ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) {
300 Archive* archive = new Archive;
301 Handle handle = Kernel::g_object_pool.Create(archive);
302 archive->name = name;
303 archive->backend = backend;
304
305 ResultCode result = MountArchive(archive);
306 if (result.IsError()) {
307 return result;
308 }
309
310 return RESULT_SUCCESS;
311}
312
313ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) {
314 // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create
315 // the archive file handles at app loading, and then keep them persistent throughout execution.
316 // Archives file handles are just reused and not actually freed until emulation shut down.
317 // Verify if real hardware works this way, or if new handles are created each time
318 if (path.GetType() == FileSys::Binary)
319 // TODO(bunnei): FixMe - this is a hack to compensate for an incorrect FileSys backend
320 // design. While the functionally of this is OK, our implementation decision to separate
321 // normal files from archive file pointers is very likely wrong.
322 // See https://github.com/citra-emu/citra/issues/205
323 return MakeResult<Handle>(archive_handle);
324
325 File* file = new File;
326 Handle handle = Kernel::g_object_pool.Create(file);
327
328 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
329 if (archive == nullptr) {
330 return InvalidHandle(ErrorModule::FS);
331 }
332 file->path = path;
333 file->backend = archive->backend->OpenFile(path, mode);
334
335 if (!file->backend) {
336 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
337 ErrorSummary::NotFound, ErrorLevel::Permanent);
338 }
339
340 return MakeResult<Handle>(handle);
341}
342
343/**
344 * Delete a File from an Archive
345 * @param archive_handle Handle to an open Archive object
346 * @param path Path to the File inside of the Archive
347 * @return Whether deletion succeeded
348 */
349Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) {
350 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
351 if (archive == nullptr)
352 return -1;
353 if (archive->backend->DeleteFile(path))
354 return 0;
355 return -1;
356}
357
358/**
359 * Delete a Directory from an Archive
360 * @param archive_handle Handle to an open Archive object
361 * @param path Path to the Directory inside of the Archive
362 * @return Whether deletion succeeded
363 */
364Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
365 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
366 if (archive == nullptr)
367 return -1;
368 if (archive->backend->DeleteDirectory(path))
369 return 0;
370 return -1;
371}
372
373/**
374 * Create a Directory from an Archive
375 * @param archive_handle Handle to an open Archive object
376 * @param path Path to the Directory inside of the Archive
377 * @return Whether creation succeeded
378 */
379Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
380 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
381 if (archive == nullptr)
382 return -1;
383 if (archive->backend->CreateDirectory(path))
384 return 0;
385 return -1;
386}
387
388/**
389 * Open a Directory from an Archive
390 * @param archive_handle Handle to an open Archive object
391 * @param path Path to the Directory inside of the Archive
392 * @return Opened Directory object
393 */
394ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
395 Directory* directory = new Directory;
396 Handle handle = Kernel::g_object_pool.Create(directory);
397
398 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
399 if (archive == nullptr) {
400 return InvalidHandle(ErrorModule::FS);
401 }
402 directory->path = path;
403 directory->backend = archive->backend->OpenDirectory(path);
404
405 return MakeResult<Handle>(handle);
406}
407
408/// Initialize archives
409void ArchiveInit() {
410 g_archive_map.clear();
411
412 // TODO(Link Mauve): Add the other archive types (see here for the known types:
413 // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished
414 // archive type is SDMC, so it is the only one getting exposed.
415
416 std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX);
417 auto archive = new FileSys::Archive_SDMC(sdmc_directory);
418 if (archive->Initialize())
419 CreateArchive(archive, "SDMC");
420 else
421 ERROR_LOG(KERNEL, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
422}
423
424/// Shutdown archives
425void ArchiveShutdown() {
426 g_archive_map.clear();
427}
428
429} // namespace Kernel