bcat: Implement IDeliveryCacheDirectoryService commands
Used to list and get directories at the root level.
This commit is contained in:
		@@ -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_)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user