bcat: Implement IDeliveryCacheFileService commands
Used to read the contents of files and access their metadata.
This commit is contained in:
parent
8812018c1d
commit
f352ad5c93
|
@ -40,6 +40,123 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushIpcInterface<IBcatService>(*backend);
|
rb.PushIpcInterface<IBcatService>(*backend);
|
||||||
|
|
||||||
|
class IDeliveryCacheFileService final : public ServiceFramework<IDeliveryCacheFileService> {
|
||||||
|
public:
|
||||||
|
IDeliveryCacheFileService(FileSys::VirtualDir root_)
|
||||||
|
: ServiceFramework{"IDeliveryCacheFileService"}, root(std::move(root_)) {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, &IDeliveryCacheFileService::Open, "Open"},
|
||||||
|
{1, &IDeliveryCacheFileService::Read, "Read"},
|
||||||
|
{2, &IDeliveryCacheFileService::GetSize, "GetSize"},
|
||||||
|
{3, &IDeliveryCacheFileService::GetDigest, "GetDigest"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Open(Kernel::HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto dir_name_raw = rp.PopRaw<DirectoryName>();
|
||||||
|
const auto file_name_raw = rp.PopRaw<FileName>();
|
||||||
|
|
||||||
|
const auto dir_name =
|
||||||
|
Common::StringFromFixedZeroTerminatedBuffer(dir_name_raw.data(), dir_name_raw.size());
|
||||||
|
const auto file_name =
|
||||||
|
Common::StringFromFixedZeroTerminatedBuffer(file_name_raw.data(), file_name_raw.size());
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_BCAT, "called, dir_name={}, file_name={}", dir_name, file_name);
|
||||||
|
|
||||||
|
if (!VerifyNameValidDir(ctx, dir_name_raw) || !VerifyNameValidFile(ctx, file_name_raw))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (current_file != 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto dir = root->GetSubdirectory(dir_name);
|
||||||
|
|
||||||
|
if (dir == nullptr) {
|
||||||
|
LOG_ERROR(Service_BCAT, "The directory of name={} couldn't be opened!", dir_name);
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ERROR_FAILED_OPEN_ENTITY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_file = dir->GetFile(file_name);
|
||||||
|
|
||||||
|
if (current_file == nullptr) {
|
||||||
|
LOG_ERROR(Service_BCAT, "The file of name={} couldn't be opened!", file_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) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto offset{rp.PopRaw<u64>()};
|
||||||
|
|
||||||
|
auto size = ctx.GetWriteBufferSize();
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_BCAT, "called, offset={:016X}, size={:016X}", offset, size);
|
||||||
|
|
||||||
|
if (current_file == nullptr) {
|
||||||
|
LOG_ERROR(Service_BCAT, "There is no file currently open!");
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ERROR_NO_OPEN_ENTITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
size = std::min(current_file->GetSize() - offset, size);
|
||||||
|
const auto buffer = current_file->ReadBytes(size, offset);
|
||||||
|
ctx.WriteBuffer(buffer);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.Push<u64>(buffer.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetSize(Kernel::HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_BCAT, "called");
|
||||||
|
|
||||||
|
if (current_file == nullptr) {
|
||||||
|
LOG_ERROR(Service_BCAT, "There is no file currently open!");
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ERROR_NO_OPEN_ENTITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.Push<u64>(current_file->GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetDigest(Kernel::HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_BCAT, "called");
|
||||||
|
|
||||||
|
if (current_file == nullptr) {
|
||||||
|
LOG_ERROR(Service_BCAT, "There is no file currently open!");
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ERROR_NO_OPEN_ENTITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 6};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.PushRaw(DigestFile(current_file));
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSys::VirtualDir root;
|
||||||
|
FileSys::VirtualFile current_file;
|
||||||
|
};
|
||||||
|
|
||||||
class IDeliveryCacheDirectoryService final
|
class IDeliveryCacheDirectoryService final
|
||||||
: public ServiceFramework<IDeliveryCacheDirectoryService> {
|
: public ServiceFramework<IDeliveryCacheDirectoryService> {
|
||||||
public:
|
public:
|
||||||
|
|
Reference in New Issue