|
|
|
@ -40,6 +40,105 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { |
|
|
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|
|
|
rb.Push(RESULT_SUCCESS); |
|
|
|
rb.PushIpcInterface<IBcatService>(*backend); |
|
|
|
class IDeliveryCacheDirectoryService final |
|
|
|
: public ServiceFramework<IDeliveryCacheDirectoryService> { |
|
|
|
public: |
|
|
|
IDeliveryCacheDirectoryService(FileSys::VirtualDir root_) |
|
|
|
: ServiceFramework{"IDeliveryCacheDirectoryService"}, root(std::move(root_)) { |
|
|
|
// clang-format off
|
|
|
|
static const FunctionInfo functions[] = { |
|
|
|
{0, &IDeliveryCacheDirectoryService::Open, "Open"}, |
|
|
|
{1, &IDeliveryCacheDirectoryService::Read, "Read"}, |
|
|
|
{2, &IDeliveryCacheDirectoryService::GetCount, "GetCount"}, |
|
|
|
}; |
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
RegisterHandlers(functions); |
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
void Open(Kernel::HLERequestContext& ctx) { |
|
|
|
IPC::RequestParser rp{ctx}; |
|
|
|
const auto name_raw = rp.PopRaw<DirectoryName>(); |
|
|
|
const auto name = |
|
|
|
Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size()); |
|
|
|
|
|
|
|
LOG_DEBUG(Service_BCAT, "called, name={}", name); |
|
|
|
|
|
|
|
if (!VerifyNameValidDir(ctx, name_raw)) |
|
|
|
return; |
|
|
|
|
|
|
|
if (current_dir != nullptr) { |
|
|
|
LOG_ERROR(Service_BCAT, "A file has already been opened on this interface!"); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ERROR_ENTITY_ALREADY_OPEN); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
current_dir = root->GetSubdirectory(name); |
|
|
|
|
|
|
|
if (current_dir == nullptr) { |
|
|
|
LOG_ERROR(Service_BCAT, "Failed to open the directory name={}!", name); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ERROR_FAILED_OPEN_ENTITY); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(RESULT_SUCCESS); |
|
|
|
} |
|
|
|
|
|
|
|
void Read(Kernel::HLERequestContext& ctx) { |
|
|
|
auto write_size = ctx.GetWriteBufferSize() / sizeof(DeliveryCacheDirectoryEntry); |
|
|
|
|
|
|
|
LOG_DEBUG(Service_BCAT, "called, write_size={:016X}", write_size); |
|
|
|
|
|
|
|
if (current_dir == nullptr) { |
|
|
|
LOG_ERROR(Service_BCAT, "There is no open directory!"); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ERROR_NO_OPEN_ENTITY); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const auto files = current_dir->GetFiles(); |
|
|
|
write_size = std::min(write_size, files.size()); |
|
|
|
std::vector<DeliveryCacheDirectoryEntry> entries(write_size); |
|
|
|
std::transform( |
|
|
|
files.begin(), files.begin() + write_size, entries.begin(), [](const auto& file) { |
|
|
|
FileName name{}; |
|
|
|
std::memcpy(name.data(), file->GetName().data(), |
|
|
|
std::min(file->GetName().size(), name.size())); |
|
|
|
return DeliveryCacheDirectoryEntry{name, file->GetSize(), DigestFile(file)}; |
|
|
|
}); |
|
|
|
|
|
|
|
ctx.WriteBuffer(entries); |
|
|
|
|
|
|
|
IPC::ResponseBuilder rb{ctx, 3}; |
|
|
|
rb.Push(RESULT_SUCCESS); |
|
|
|
rb.Push<u32>(write_size * sizeof(DeliveryCacheDirectoryEntry)); |
|
|
|
} |
|
|
|
|
|
|
|
void GetCount(Kernel::HLERequestContext& ctx) { |
|
|
|
LOG_DEBUG(Service_BCAT, "called"); |
|
|
|
|
|
|
|
if (current_dir == nullptr) { |
|
|
|
LOG_ERROR(Service_BCAT, "There is no open directory!"); |
|
|
|
IPC::ResponseBuilder rb{ctx, 2}; |
|
|
|
rb.Push(ERROR_NO_OPEN_ENTITY); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const auto files = current_dir->GetFiles(); |
|
|
|
|
|
|
|
IPC::ResponseBuilder rb{ctx, 3}; |
|
|
|
rb.Push(RESULT_SUCCESS); |
|
|
|
rb.Push<u32>(files.size()); |
|
|
|
} |
|
|
|
|
|
|
|
FileSys::VirtualDir root; |
|
|
|
FileSys::VirtualDir current_dir; |
|
|
|
}; |
|
|
|
|
|
|
|
class IDeliveryCacheStorageService final : public ServiceFramework<IDeliveryCacheStorageService> { |
|
|
|
public: |
|
|
|
IDeliveryCacheStorageService(FileSys::VirtualDir root_) |
|
|
|
|