mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	service/cecd: Update handling of /outbox/boxinfo and /outbox/obindex
This commit is contained in:
		
							parent
							
								
									648cecf1aa
								
							
						
					
					
						commit
						192a0f3b92
					
				
					 2 changed files with 277 additions and 33 deletions
				
			
		|  | @ -3,6 +3,7 @@ | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
| #include <cryptopp/base64.h> | #include <cryptopp/base64.h> | ||||||
|  | #include <cryptopp/hmac.h> | ||||||
| #include "common/file_util.h" | #include "common/file_util.h" | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "common/string_util.h" | #include "common/string_util.h" | ||||||
|  | @ -187,6 +188,26 @@ void Module::Interface::ReadMessage(Kernel::HLERequestContext& ctx) { | ||||||
|         write_buffer.Write(buffer.data(), 0, buffer_size); |         write_buffer.Write(buffer.data(), 0, buffer_size); | ||||||
|         message->backend->Close(); |         message->backend->Close(); | ||||||
| 
 | 
 | ||||||
|  |         CecMessageHeader msg_header; | ||||||
|  | 
 | ||||||
|  |         std::memcpy(&msg_header, buffer.data(), sizeof(CecMessageHeader)); | ||||||
|  |         LOG_DEBUG(Service_CECD, | ||||||
|  |                   "magic={:#06x}, message_size={:#010x}, header_size={:#010x}, " | ||||||
|  |                   "body_size={:#010x}, title_id={:#010x}, title_id_2={:#010x}, " | ||||||
|  |                   "batch_id={:#010x}", | ||||||
|  |                   msg_header.magic, msg_header.message_size, msg_header.header_size, | ||||||
|  |                   msg_header.body_size, msg_header.title_id, msg_header.title_id2, | ||||||
|  |                   msg_header.batch_id); | ||||||
|  |         LOG_DEBUG(Service_CECD, | ||||||
|  |                   "unknown_id={:#010x}, version={:#010x}, flag={:#04x}, " | ||||||
|  |                   "send_method={:#04x}, is_unopen={:#04x}, is_new={:#04x}, " | ||||||
|  |                   "sender_id={:#018x}, sender_id2={:#018x}, send_count={:#04x}, " | ||||||
|  |                   "forward_count={:#04x}, user_data={:#06x}, ", | ||||||
|  |                   msg_header.unknown_id, msg_header.version, msg_header.flag, | ||||||
|  |                   msg_header.send_method, msg_header.is_unopen, msg_header.is_new, | ||||||
|  |                   msg_header.sender_id, msg_header.sender_id2, msg_header.send_count, | ||||||
|  |                   msg_header.forward_count, msg_header.user_data); | ||||||
|  | 
 | ||||||
|         rb.Push(RESULT_SUCCESS); |         rb.Push(RESULT_SUCCESS); | ||||||
|         rb.Push<u32>(bytes_read); |         rb.Push<u32>(bytes_read); | ||||||
|     } else { |     } else { | ||||||
|  | @ -239,6 +260,26 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) { | ||||||
|         write_buffer.Write(buffer.data(), 0, buffer_size); |         write_buffer.Write(buffer.data(), 0, buffer_size); | ||||||
|         message->backend->Close(); |         message->backend->Close(); | ||||||
| 
 | 
 | ||||||
|  |         CecMessageHeader msg_header; | ||||||
|  | 
 | ||||||
|  |         std::memcpy(&msg_header, buffer.data(), sizeof(CecMessageHeader)); | ||||||
|  |         LOG_DEBUG(Service_CECD, | ||||||
|  |                   "magic={:#06x}, message_size={:#010x}, header_size={:#010x}, " | ||||||
|  |                   "body_size={:#010x}, title_id={:#010x}, title_id_2={:#010x}, " | ||||||
|  |                   "batch_id={:#010x}", | ||||||
|  |                   msg_header.magic, msg_header.message_size, msg_header.header_size, | ||||||
|  |                   msg_header.body_size, msg_header.title_id, msg_header.title_id2, | ||||||
|  |                   msg_header.batch_id); | ||||||
|  |         LOG_DEBUG(Service_CECD, | ||||||
|  |                   "unknown_id={:#010x}, version={:#010x}, flag={:#04x}, " | ||||||
|  |                   "send_method={:#04x}, is_unopen={:#04x}, is_new={:#04x}, " | ||||||
|  |                   "sender_id={:#018x}, sender_id2={:#018x}, send_count={:#04x}, " | ||||||
|  |                   "forward_count={:#04x}, user_data={:#06x}, ", | ||||||
|  |                   msg_header.unknown_id, msg_header.version, msg_header.flag, | ||||||
|  |                   msg_header.send_method, msg_header.is_unopen, msg_header.is_new, | ||||||
|  |                   msg_header.sender_id, msg_header.sender_id2, msg_header.send_count, | ||||||
|  |                   msg_header.forward_count, msg_header.user_data); | ||||||
|  | 
 | ||||||
|         rb.Push(RESULT_SUCCESS); |         rb.Push(RESULT_SUCCESS); | ||||||
|         rb.Push<u32>(bytes_read); |         rb.Push<u32>(bytes_read); | ||||||
|     } else { |     } else { | ||||||
|  | @ -285,13 +326,17 @@ void Module::Interface::Write(Kernel::HLERequestContext& ctx) { | ||||||
|         std::vector<u8> buffer(read_buffer_size); |         std::vector<u8> buffer(read_buffer_size); | ||||||
|         read_buffer.Read(buffer.data(), 0, read_buffer_size); |         read_buffer.Read(buffer.data(), 0, read_buffer_size); | ||||||
| 
 | 
 | ||||||
|  |         if (session_data->file->backend->GetSize() != read_buffer_size) { | ||||||
|  |             session_data->file->backend->SetSize(read_buffer_size); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if (session_data->open_mode.check) { |         if (session_data->open_mode.check) { | ||||||
|             cecd->CheckAndUpdateFile(session_data->data_path_type, session_data->ncch_program_id, |             cecd->CheckAndUpdateFile(session_data->data_path_type, session_data->ncch_program_id, | ||||||
|                                      buffer); |                                      buffer); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const u32 bytes_written = |         const u32 bytes_written = | ||||||
|             session_data->file->backend->Write(0, read_buffer_size, true, buffer.data()).Unwrap(); |             session_data->file->backend->Write(0, buffer.size(), true, buffer.data()).Unwrap(); | ||||||
|         session_data->file->backend->Close(); |         session_data->file->backend->Close(); | ||||||
| 
 | 
 | ||||||
|         rb.Push(RESULT_SUCCESS); |         rb.Push(RESULT_SUCCESS); | ||||||
|  | @ -330,8 +375,27 @@ void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) { | ||||||
|     if (message_result.Succeeded()) { |     if (message_result.Succeeded()) { | ||||||
|         auto message = message_result.Unwrap(); |         auto message = message_result.Unwrap(); | ||||||
|         std::vector<u8> buffer(buffer_size); |         std::vector<u8> buffer(buffer_size); | ||||||
|  |         CecMessageHeader msg_header; | ||||||
| 
 | 
 | ||||||
|         read_buffer.Read(buffer.data(), 0, buffer_size); |         read_buffer.Read(buffer.data(), 0, buffer_size); | ||||||
|  |         std::memcpy(&msg_header, buffer.data(), sizeof(CecMessageHeader)); | ||||||
|  |         LOG_DEBUG(Service_CECD, | ||||||
|  |                   "magic={:#06x}, message_size={:#010x}, header_size={:#010x}, " | ||||||
|  |                   "body_size={:#010x}, title_id={:#010x}, title_id_2={:#010x}, " | ||||||
|  |                   "batch_id={:#010x}", | ||||||
|  |                   msg_header.magic, msg_header.message_size, msg_header.header_size, | ||||||
|  |                   msg_header.body_size, msg_header.title_id, msg_header.title_id2, | ||||||
|  |                   msg_header.batch_id); | ||||||
|  |         LOG_DEBUG(Service_CECD, | ||||||
|  |                   "unknown_id={:#010x}, version={:#010x}, flag={:#04x}, " | ||||||
|  |                   "send_method={:#04x}, is_unopen={:#04x}, is_new={:#04x}, " | ||||||
|  |                   "sender_id={:#018x}, sender_id2={:#018x}, send_count={:#04x}, " | ||||||
|  |                   "forward_count={:#04x}, user_data={:#06x}, ", | ||||||
|  |                   msg_header.unknown_id, msg_header.version, msg_header.flag, | ||||||
|  |                   msg_header.send_method, msg_header.is_unopen, msg_header.is_new, | ||||||
|  |                   msg_header.sender_id, msg_header.sender_id2, msg_header.send_count, | ||||||
|  |                   msg_header.forward_count, msg_header.user_data); | ||||||
|  | 
 | ||||||
|         const u32 bytes_written = |         const u32 bytes_written = | ||||||
|             message->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); |             message->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); | ||||||
|         message->backend->Close(); |         message->backend->Close(); | ||||||
|  | @ -383,8 +447,27 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) { | ||||||
|     if (message_result.Succeeded()) { |     if (message_result.Succeeded()) { | ||||||
|         auto message = message_result.Unwrap(); |         auto message = message_result.Unwrap(); | ||||||
|         std::vector<u8> buffer(buffer_size); |         std::vector<u8> buffer(buffer_size); | ||||||
|  |         CecMessageHeader msg_header; | ||||||
| 
 | 
 | ||||||
|         read_buffer.Read(buffer.data(), 0, buffer_size); |         read_buffer.Read(buffer.data(), 0, buffer_size); | ||||||
|  |         std::memcpy(&msg_header, buffer.data(), sizeof(CecMessageHeader)); | ||||||
|  |         LOG_DEBUG(Service_CECD, | ||||||
|  |                   "magic={:#06x}, message_size={:#010x}, header_size={:#010x}, " | ||||||
|  |                   "body_size={:#010x}, title_id={:#010x}, title_id_2={:#010x}, " | ||||||
|  |                   "batch_id={:#010x}", | ||||||
|  |                   msg_header.magic, msg_header.message_size, msg_header.header_size, | ||||||
|  |                   msg_header.body_size, msg_header.title_id, msg_header.title_id2, | ||||||
|  |                   msg_header.batch_id); | ||||||
|  |         LOG_DEBUG(Service_CECD, | ||||||
|  |                   "unknown_id={:#010x}, version={:#010x}, flag={:#04x}, " | ||||||
|  |                   "send_method={:#04x}, is_unopen={:#04x}, is_new={:#04x}, " | ||||||
|  |                   "sender_id={:#018x}, sender_id2={:#018x}, send_count={:#04x}, " | ||||||
|  |                   "forward_count={:#04x}, user_data={:#06x}, ", | ||||||
|  |                   msg_header.unknown_id, msg_header.version, msg_header.flag, | ||||||
|  |                   msg_header.send_method, msg_header.is_unopen, msg_header.is_new, | ||||||
|  |                   msg_header.sender_id, msg_header.sender_id2, msg_header.send_count, | ||||||
|  |                   msg_header.forward_count, msg_header.user_data); | ||||||
|  | 
 | ||||||
|         const u32 bytes_written = |         const u32 bytes_written = | ||||||
|             message->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); |             message->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); | ||||||
|         message->backend->Close(); |         message->backend->Close(); | ||||||
|  | @ -457,26 +540,32 @@ void Module::Interface::SetData(Kernel::HLERequestContext& ctx) { | ||||||
|     const u32 ncch_program_id = rp.Pop<u32>(); |     const u32 ncch_program_id = rp.Pop<u32>(); | ||||||
|     const u32 buffer_size = rp.Pop<u32>(); |     const u32 buffer_size = rp.Pop<u32>(); | ||||||
|     const u32 option = rp.Pop<u32>(); |     const u32 option = rp.Pop<u32>(); | ||||||
|     auto& message_id_buffer = rp.PopMappedBuffer(); |     auto& read_buffer = rp.PopMappedBuffer(); | ||||||
| 
 | 
 | ||||||
|     SessionData* session_data = GetSessionData(ctx.Session()); |     if (option == 2 && buffer_size > 0) { // update obindex?
 | ||||||
|     if (session_data->file) |         FileSys::Path path( | ||||||
|         LOG_TRACE( |             cecd->GetCecDataPathTypeAsString(CecDataPathType::OutboxIndex, ncch_program_id).data()); | ||||||
|             Service_CECD, |         FileSys::Mode mode; | ||||||
|             "SessionData: ncch_program_id={:#010x}, data_path_type={:#04x}, " |         mode.write_flag.Assign(1); | ||||||
|             "path={}, open_mode: raw={:#x}, unknown={}, read={}, write={}, create={}, check={}", |         mode.create_flag.Assign(1); | ||||||
|             session_data->ncch_program_id, static_cast<u32>(session_data->data_path_type), |  | ||||||
|             session_data->path.AsString(), session_data->open_mode.raw, |  | ||||||
|             session_data->open_mode.unknown, session_data->open_mode.read, |  | ||||||
|             session_data->open_mode.write, session_data->open_mode.create, |  | ||||||
|             session_data->open_mode.check); |  | ||||||
| 
 | 
 | ||||||
|     if (session_data->file) |         auto file_result = | ||||||
|         session_data->file->backend->Close(); |             Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, mode); | ||||||
|  |         if (file_result.Succeeded()) { | ||||||
|  |             auto file = file_result.Unwrap(); | ||||||
|  |             std::vector<u8> buffer(buffer_size); | ||||||
|  |             read_buffer.Read(buffer.data(), 0, buffer_size); | ||||||
|  | 
 | ||||||
|  |             cecd->CheckAndUpdateFile(CecDataPathType::OutboxIndex, ncch_program_id, buffer); | ||||||
|  | 
 | ||||||
|  |             file->backend->Write(0, buffer.size(), true, buffer.data()); | ||||||
|  |             file->backend->Close(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|     rb.PushMappedBuffer(message_id_buffer); |     rb.PushMappedBuffer(read_buffer); | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_CECD, "called, ncch_program_id={:#010x}, buffer_size={:#x}, option={:#x}", |     LOG_DEBUG(Service_CECD, "called, ncch_program_id={:#010x}, buffer_size={:#x}, option={:#x}", | ||||||
|               ncch_program_id, buffer_size, option); |               ncch_program_id, buffer_size, option); | ||||||
|  | @ -612,15 +701,20 @@ void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) { | ||||||
|             Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, mode); |             Service::FS::OpenFileFromArchive(cecd->cecd_system_save_data_archive, path, mode); | ||||||
|         if (file_result.Succeeded()) { |         if (file_result.Succeeded()) { | ||||||
|             auto file = file_result.Unwrap(); |             auto file = file_result.Unwrap(); | ||||||
|  | 
 | ||||||
|             std::vector<u8> buffer(buffer_size); |             std::vector<u8> buffer(buffer_size); | ||||||
|             read_buffer.Read(buffer.data(), 0, buffer_size); |             read_buffer.Read(buffer.data(), 0, buffer_size); | ||||||
| 
 | 
 | ||||||
|  |             if (file->backend->GetSize() != buffer_size) { | ||||||
|  |                 file->backend->SetSize(buffer_size); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             if (open_mode.check) { |             if (open_mode.check) { | ||||||
|                 cecd->CheckAndUpdateFile(path_type, ncch_program_id, buffer); |                 cecd->CheckAndUpdateFile(path_type, ncch_program_id, buffer); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             const u32 bytes_written = |             const u32 bytes_written = | ||||||
|                 file->backend->Write(0, buffer_size, true, buffer.data()).Unwrap(); |                 file->backend->Write(0, buffer.size(), true, buffer.data()).Unwrap(); | ||||||
|             file->backend->Close(); |             file->backend->Close(); | ||||||
| 
 | 
 | ||||||
|             rb.Push(RESULT_SUCCESS); |             rb.Push(RESULT_SUCCESS); | ||||||
|  | @ -808,6 +902,9 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ | ||||||
|         CecMBoxListHeader mbox_list_header = {}; |         CecMBoxListHeader mbox_list_header = {}; | ||||||
|         std::memcpy(&mbox_list_header, file_buffer.data(), sizeof(CecMBoxListHeader)); |         std::memcpy(&mbox_list_header, file_buffer.data(), sizeof(CecMBoxListHeader)); | ||||||
| 
 | 
 | ||||||
|  |         LOG_DEBUG(Service_CECD, "CecMBoxList: magic={:#06x}, version={:#06x}, num_boxes={:#06x}", | ||||||
|  |                   mbox_list_header.magic, mbox_list_header.version, mbox_list_header.num_boxes); | ||||||
|  | 
 | ||||||
|         if (file_size != sizeof(CecMBoxListHeader)) { // 0x18C
 |         if (file_size != sizeof(CecMBoxListHeader)) { // 0x18C
 | ||||||
|             LOG_DEBUG(Service_CECD, "CecMBoxListHeader size is incorrect: {}", file_size); |             LOG_DEBUG(Service_CECD, "CecMBoxListHeader size is incorrect: {}", file_size); | ||||||
|         } |         } | ||||||
|  | @ -845,7 +942,6 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ | ||||||
| 
 | 
 | ||||||
|                 bool already_activated = false; |                 bool already_activated = false; | ||||||
|                 for (auto i = 0; i < mbox_list_header.num_boxes; i++) { |                 for (auto i = 0; i < mbox_list_header.num_boxes; i++) { | ||||||
|                     LOG_DEBUG(Service_CECD, "{}", i); |  | ||||||
|                     // Box names start at offset 0xC, are 16 char long, first 8 id, last 8 null
 |                     // Box names start at offset 0xC, are 16 char long, first 8 id, last 8 null
 | ||||||
|                     if (std::memcmp(name_buffer.data(), &mbox_list_header.box_names[i], |                     if (std::memcmp(name_buffer.data(), &mbox_list_header.box_names[i], | ||||||
|                                     valid_name_size) == 0) { |                                     valid_name_size) == 0) { | ||||||
|  | @ -903,6 +999,12 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ | ||||||
|         CecMBoxInfoHeader mbox_info_header = {}; |         CecMBoxInfoHeader mbox_info_header = {}; | ||||||
|         std::memcpy(&mbox_info_header, file_buffer.data(), sizeof(CecMBoxInfoHeader)); |         std::memcpy(&mbox_info_header, file_buffer.data(), sizeof(CecMBoxInfoHeader)); | ||||||
| 
 | 
 | ||||||
|  |         LOG_DEBUG(Service_CECD, | ||||||
|  |                   "CecMBoxInfoHeader: magic={:#06x}, program_id={:#010x}, " | ||||||
|  |                   "private_id={:#010x}, flag={:#04x}, flag2={:#04x}", | ||||||
|  |                   mbox_info_header.magic, mbox_info_header.program_id, mbox_info_header.private_id, | ||||||
|  |                   mbox_info_header.flag, mbox_info_header.flag2); | ||||||
|  | 
 | ||||||
|         if (file_size != sizeof(CecMBoxInfoHeader)) { // 0x60
 |         if (file_size != sizeof(CecMBoxInfoHeader)) { // 0x60
 | ||||||
|             LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader size is incorrect: {}", file_size); |             LOG_DEBUG(Service_CECD, "CecMBoxInfoHeader size is incorrect: {}", file_size); | ||||||
|         } |         } | ||||||
|  | @ -928,8 +1030,18 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case CecDataPathType::InboxInfo: { |     case CecDataPathType::InboxInfo: { | ||||||
|         CecInOutBoxInfoHeader inbox_info_header = {}; |         CecBoxInfoHeader inbox_info_header = {}; | ||||||
|         std::memcpy(&inbox_info_header, file_buffer.data(), sizeof(CecInOutBoxInfoHeader)); |         std::memcpy(&inbox_info_header, file_buffer.data(), sizeof(CecBoxInfoHeader)); | ||||||
|  | 
 | ||||||
|  |         LOG_DEBUG(Service_CECD, | ||||||
|  |                   "CecBoxInfoHeader: magic={:#06x}, box_info_size={:#010x}, " | ||||||
|  |                   "max_box_size={:#010x}, box_size={:#010x}, " | ||||||
|  |                   "max_message_num={:#010x}, message_num={:#010x}, " | ||||||
|  |                   "max_batch_size={:#010x}, max_message_size={:#010x}", | ||||||
|  |                   inbox_info_header.magic, inbox_info_header.box_info_size, | ||||||
|  |                   inbox_info_header.max_box_size, inbox_info_header.box_size, | ||||||
|  |                   inbox_info_header.max_message_num, inbox_info_header.message_num, | ||||||
|  |                   inbox_info_header.max_batch_size, inbox_info_header.max_message_size); | ||||||
| 
 | 
 | ||||||
|         if (inbox_info_header.magic != 0x6262) { // 'bb'
 |         if (inbox_info_header.magic != 0x6262) { // 'bb'
 | ||||||
|             if (inbox_info_header.magic == 0) |             if (inbox_info_header.magic == 0) | ||||||
|  | @ -946,7 +1058,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ | ||||||
|             else |             else | ||||||
|                 LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader box info size is incorrect:", |                 LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader box info size is incorrect:", | ||||||
|                           inbox_info_header.box_info_size); |                           inbox_info_header.box_info_size); | ||||||
|             inbox_info_header.box_info_size = sizeof(CecInOutBoxInfoHeader); |             inbox_info_header.box_info_size = sizeof(CecBoxInfoHeader); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (inbox_info_header.max_box_size == 0) { |         if (inbox_info_header.max_box_size == 0) { | ||||||
|  | @ -976,12 +1088,22 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ | ||||||
|             LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max batch size != max message number"); |             LOG_DEBUG(Service_CECD, "CecInBoxInfoHeader max batch size != max message number"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         std::memcpy(file_buffer.data(), &inbox_info_header, sizeof(CecInOutBoxInfoHeader)); |         std::memcpy(file_buffer.data(), &inbox_info_header, sizeof(CecBoxInfoHeader)); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case CecDataPathType::OutboxInfo: { |     case CecDataPathType::OutboxInfo: { | ||||||
|         CecInOutBoxInfoHeader outbox_info_header = {}; |         CecBoxInfoHeader outbox_info_header = {}; | ||||||
|         std::memcpy(&outbox_info_header, file_buffer.data(), sizeof(CecInOutBoxInfoHeader)); |         std::memcpy(&outbox_info_header, file_buffer.data(), sizeof(CecBoxInfoHeader)); | ||||||
|  | 
 | ||||||
|  |         LOG_DEBUG(Service_CECD, | ||||||
|  |                   "CecBoxInfoHeader: magic={:#06x}, box_info_size={:#010x}, " | ||||||
|  |                   "max_box_size={:#010x}, box_size={:#010x}, " | ||||||
|  |                   "max_message_num={:#010x}, message_num={:#010x}, " | ||||||
|  |                   "max_batch_size={:#010x}, max_message_size={:#010x}", | ||||||
|  |                   outbox_info_header.magic, outbox_info_header.box_info_size, | ||||||
|  |                   outbox_info_header.max_box_size, outbox_info_header.box_size, | ||||||
|  |                   outbox_info_header.max_message_num, outbox_info_header.message_num, | ||||||
|  |                   outbox_info_header.max_batch_size, outbox_info_header.max_message_size); | ||||||
| 
 | 
 | ||||||
|         if (outbox_info_header.magic != 0x6262) { // 'bb'
 |         if (outbox_info_header.magic != 0x6262) { // 'bb'
 | ||||||
|             if (outbox_info_header.magic == 0) |             if (outbox_info_header.magic == 0) | ||||||
|  | @ -992,13 +1114,14 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ | ||||||
|             outbox_info_header.magic = 0x6262; |             outbox_info_header.magic = 0x6262; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (outbox_info_header.box_info_size != file_size) { |         if (outbox_info_header.box_info_size != file_buffer.size()) { | ||||||
|             if (outbox_info_header.box_info_size == 0) |             if (outbox_info_header.box_info_size == 0) | ||||||
|                 LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader box info size is not set"); |                 LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader box info size is not set"); | ||||||
|             else |             else | ||||||
|                 LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader box info size is incorrect:", |                 LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader box info size is incorrect:", | ||||||
|                           outbox_info_header.box_info_size); |                           outbox_info_header.box_info_size); | ||||||
|             outbox_info_header.box_info_size = sizeof(CecInOutBoxInfoHeader); |             outbox_info_header.box_info_size = sizeof(CecBoxInfoHeader); | ||||||
|  |             outbox_info_header.message_num = 0; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (outbox_info_header.max_box_size == 0) { |         if (outbox_info_header.max_box_size == 0) { | ||||||
|  | @ -1026,7 +1149,71 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ | ||||||
|             LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max batch size != max message number"); |             LOG_DEBUG(Service_CECD, "CecOutBoxInfoHeader max batch size != max message number"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         std::memcpy(file_buffer.data(), &outbox_info_header, sizeof(CecInOutBoxInfoHeader)); |         /// We need to read the /CEC/<id>/OutBox directory to find out which messages, if any,
 | ||||||
|  |         /// are present. The num_of_messages = (total_read_count) - 2, to adjust for
 | ||||||
|  |         /// the BoxInfo____ and OBIndex_____files that are present in the directory as well.
 | ||||||
|  |         FileSys::Path outbox_path( | ||||||
|  |             GetCecDataPathTypeAsString(CecDataPathType::OutboxDir, ncch_program_id).data()); | ||||||
|  | 
 | ||||||
|  |         auto dir_result = | ||||||
|  |             Service::FS::OpenDirectoryFromArchive(cecd_system_save_data_archive, outbox_path); | ||||||
|  | 
 | ||||||
|  |         auto outbox_dir = dir_result.Unwrap(); | ||||||
|  |         std::vector<FileSys::Entry> entries(outbox_info_header.max_message_num + 2); | ||||||
|  |         const u32 entry_count = | ||||||
|  |             outbox_dir->backend->Read(outbox_info_header.max_message_num + 2, entries.data()); | ||||||
|  |         outbox_dir->backend->Close(); | ||||||
|  | 
 | ||||||
|  |         LOG_DEBUG(Service_CECD, "Number of entries found in /OutBox: {}", entry_count); | ||||||
|  |         std::array<CecMessageHeader, 8> message_headers; | ||||||
|  | 
 | ||||||
|  |         std::string boxinfo_name("BoxInfo_____"); | ||||||
|  |         std::string obindex_name("OBIndex_____"); | ||||||
|  |         std::string file_name; | ||||||
|  |         std::u16string u16_filename; | ||||||
|  | 
 | ||||||
|  |         for (auto i = 0; i < entry_count; i++) { | ||||||
|  |             u16_filename = std::u16string(entries[i].filename); | ||||||
|  |             file_name = Common::UTF16ToUTF8(u16_filename); | ||||||
|  | 
 | ||||||
|  |             if (boxinfo_name.compare(file_name) != 0 && obindex_name.compare(file_name) != 0) { | ||||||
|  |                 LOG_DEBUG(Service_CECD, "Adding message to BoxInfo_____: {}", file_name); | ||||||
|  | 
 | ||||||
|  |                 FileSys::Path message_path( | ||||||
|  |                     (GetCecDataPathTypeAsString(CecDataPathType::OutboxDir, ncch_program_id) + "/" + | ||||||
|  |                      file_name) | ||||||
|  |                         .data()); | ||||||
|  | 
 | ||||||
|  |                 FileSys::Mode mode; | ||||||
|  |                 mode.read_flag.Assign(1); | ||||||
|  | 
 | ||||||
|  |                 auto message_result = Service::FS::OpenFileFromArchive( | ||||||
|  |                     cecd_system_save_data_archive, message_path, mode); | ||||||
|  | 
 | ||||||
|  |                 auto message = message_result.Unwrap(); | ||||||
|  |                 const u32 message_size = message->backend->GetSize(); | ||||||
|  |                 std::vector<u8> buffer(message_size); | ||||||
|  | 
 | ||||||
|  |                 message->backend->Read(0, message_size, buffer.data()).Unwrap(); | ||||||
|  |                 message->backend->Close(); | ||||||
|  | 
 | ||||||
|  |                 std::memcpy(&message_headers[outbox_info_header.message_num++], buffer.data(), | ||||||
|  |                             sizeof(CecMessageHeader)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (outbox_info_header.message_num > 0) { | ||||||
|  |             const u32 message_headers_size = | ||||||
|  |                 outbox_info_header.message_num * sizeof(CecMessageHeader); | ||||||
|  | 
 | ||||||
|  |             file_buffer.resize(sizeof(CecBoxInfoHeader) + message_headers_size, 0); | ||||||
|  |             outbox_info_header.box_info_size += message_headers_size; | ||||||
|  | 
 | ||||||
|  |             std::memcpy(file_buffer.data() + sizeof(CecBoxInfoHeader), &message_headers, | ||||||
|  |                         message_headers_size); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         std::memcpy(file_buffer.data(), &outbox_info_header, sizeof(CecBoxInfoHeader)); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case CecDataPathType::OutboxIndex: { |     case CecDataPathType::OutboxIndex: { | ||||||
|  | @ -1054,6 +1241,64 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_ | ||||||
|         } else if (obindex_header.message_num != (file_size % 8) - 1) { |         } else if (obindex_header.message_num != (file_size % 8) - 1) { | ||||||
|             LOG_DEBUG(Service_CECD, "CecOBIndexHeader message number is incorrect: {}", |             LOG_DEBUG(Service_CECD, "CecOBIndexHeader message number is incorrect: {}", | ||||||
|                       obindex_header.message_num); |                       obindex_header.message_num); | ||||||
|  |             obindex_header.message_num = 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// We need to read the /CEC/<id>/OutBox directory to find out which messages, if any,
 | ||||||
|  |         /// are present. The num_of_messages = (total_read_count) - 2, to adjust for
 | ||||||
|  |         /// the BoxInfo____ and OBIndex_____files that are present in the directory as well.
 | ||||||
|  |         FileSys::Path outbox_path( | ||||||
|  |             GetCecDataPathTypeAsString(CecDataPathType::OutboxDir, ncch_program_id).data()); | ||||||
|  | 
 | ||||||
|  |         auto dir_result = | ||||||
|  |             Service::FS::OpenDirectoryFromArchive(cecd_system_save_data_archive, outbox_path); | ||||||
|  | 
 | ||||||
|  |         auto outbox_dir = dir_result.Unwrap(); | ||||||
|  |         std::vector<FileSys::Entry> entries(8); | ||||||
|  |         const u32 entry_count = outbox_dir->backend->Read(8, entries.data()); | ||||||
|  |         outbox_dir->backend->Close(); | ||||||
|  | 
 | ||||||
|  |         LOG_DEBUG(Service_CECD, "Number of entries found in /OutBox: {}", entry_count); | ||||||
|  |         std::array<std::array<u8, 8>, 8> message_ids; | ||||||
|  | 
 | ||||||
|  |         std::string boxinfo_name("BoxInfo_____"); | ||||||
|  |         std::string obindex_name("OBIndex_____"); | ||||||
|  |         std::string file_name; | ||||||
|  |         std::u16string u16_filename; | ||||||
|  | 
 | ||||||
|  |         for (auto i = 0; i < entry_count; i++) { | ||||||
|  |             u16_filename = std::u16string(entries[i].filename); | ||||||
|  |             file_name = Common::UTF16ToUTF8(u16_filename); | ||||||
|  | 
 | ||||||
|  |             if (boxinfo_name.compare(file_name) != 0 && obindex_name.compare(file_name) != 0) { | ||||||
|  |                 FileSys::Path message_path( | ||||||
|  |                     (GetCecDataPathTypeAsString(CecDataPathType::OutboxDir, ncch_program_id) + "/" + | ||||||
|  |                      file_name) | ||||||
|  |                         .data()); | ||||||
|  | 
 | ||||||
|  |                 FileSys::Mode mode; | ||||||
|  |                 mode.read_flag.Assign(1); | ||||||
|  | 
 | ||||||
|  |                 auto message_result = Service::FS::OpenFileFromArchive( | ||||||
|  |                     cecd_system_save_data_archive, message_path, mode); | ||||||
|  | 
 | ||||||
|  |                 auto message = message_result.Unwrap(); | ||||||
|  |                 const u32 message_size = message->backend->GetSize(); | ||||||
|  |                 std::vector<u8> buffer(message_size); | ||||||
|  | 
 | ||||||
|  |                 message->backend->Read(0, message_size, buffer.data()).Unwrap(); | ||||||
|  |                 message->backend->Close(); | ||||||
|  | 
 | ||||||
|  |                 // Message id is at offset 0x20, and is 8 bytes
 | ||||||
|  |                 std::memcpy(&message_ids[obindex_header.message_num++], buffer.data() + 0x20, 8); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (obindex_header.message_num > 0) { | ||||||
|  |             const u32 message_ids_size = obindex_header.message_num * 8; | ||||||
|  |             file_buffer.resize(sizeof(CecOBIndexHeader) + message_ids_size); | ||||||
|  |             std::memcpy(file_buffer.data() + sizeof(CecOBIndexHeader), &message_ids, | ||||||
|  |                         message_ids_size); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         std::memcpy(file_buffer.data(), &obindex_header, sizeof(CecOBIndexHeader)); |         std::memcpy(file_buffer.data(), &obindex_header, sizeof(CecOBIndexHeader)); | ||||||
|  |  | ||||||
|  | @ -100,7 +100,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     enum class CecSystemInfoType : u32 { EulaVersion = 1, Eula = 2, ParentControl = 3 }; |     enum class CecSystemInfoType : u32 { EulaVersion = 1, Eula = 2, ParentControl = 3 }; | ||||||
| 
 | 
 | ||||||
|     struct CecInOutBoxInfoHeader { |     struct CecBoxInfoHeader { | ||||||
|         u16_le magic; // 0x6262 'bb'
 |         u16_le magic; // 0x6262 'bb'
 | ||||||
|         INSERT_PADDING_BYTES(2); |         INSERT_PADDING_BYTES(2); | ||||||
|         u32_le box_info_size; |         u32_le box_info_size; | ||||||
|  | @ -111,8 +111,7 @@ public: | ||||||
|         u32_le max_batch_size; |         u32_le max_batch_size; | ||||||
|         u32_le max_message_size; |         u32_le max_message_size; | ||||||
|     }; |     }; | ||||||
|     static_assert(sizeof(CecInOutBoxInfoHeader) == 0x20, |     static_assert(sizeof(CecBoxInfoHeader) == 0x20, "CecBoxInfoHeader struct has incorrect size."); | ||||||
|                   "CecInOutBoxInfoHeader struct has incorrect size."); |  | ||||||
| 
 | 
 | ||||||
|     struct CecMBoxInfoHeader { |     struct CecMBoxInfoHeader { | ||||||
|         u16_le magic; // 0x6363 'cc'
 |         u16_le magic; // 0x6363 'cc'
 | ||||||
|  | @ -163,13 +162,13 @@ public: | ||||||
|         u32_le body_size; |         u32_le body_size; | ||||||
| 
 | 
 | ||||||
|         u32_le title_id; |         u32_le title_id; | ||||||
|         u32_le title_id_2; |         u32_le title_id2; | ||||||
|         u32_le batch_id; |         u32_le batch_id; | ||||||
|         u32_le unknown_id; |         u32_le unknown_id; | ||||||
| 
 | 
 | ||||||
|         std::array<u8, 8> message_id; |         std::array<u8, 8> message_id; | ||||||
|         u32_le version; |         u32_le version; | ||||||
|         std::array<u8, 8> message_id_2; |         std::array<u8, 8> message_id2; | ||||||
|         u8 flag; |         u8 flag; | ||||||
|         u8 send_method; |         u8 send_method; | ||||||
|         u8 is_unopen; |         u8 is_unopen; | ||||||
|  | @ -188,7 +187,7 @@ public: | ||||||
|             u8 padding; |             u8 padding; | ||||||
|         } send_time, recv_time, create_time; |         } send_time, recv_time, create_time; | ||||||
|         u8 send_count; |         u8 send_count; | ||||||
|         u8 foward_count; |         u8 forward_count; | ||||||
|         u16_le user_data; |         u16_le user_data; | ||||||
|     }; |     }; | ||||||
|     static_assert(sizeof(CecMessageHeader) == 0x70, "CecMessageHeader struct has incorrect size."); |     static_assert(sizeof(CecMessageHeader) == 0x70, "CecMessageHeader struct has incorrect size."); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue