blob: b498d1f704d7db737629f8bb84af135e93cb5c38 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "connect.h"
namespace compat {
void FindDirectoryEntries(fidl::ClientEnd<fuchsia_io::Directory> dir,
async_dispatcher_t* dispatcher, EntriesCallback cb) {
auto client = fidl::WireSharedClient<fuchsia_io::Directory>(std::move(dir), dispatcher);
auto copy = client.Clone();
// NOTE: It would be nicer to call Watch, but that is not supported in the component's
// VFS implementation.
client->ReadDirents(fuchsia_io::wire::kMaxBuf)
.Then([client = std::move(copy), cb = std::move(cb)](
fidl::WireUnownedResult<::fuchsia_io::Directory::ReadDirents>& result) mutable {
// The format of the packed dirent structure, taken from io.fidl.
struct dirent {
// Describes the inode of the entry.
uint64_t ino;
// Describes the length of the dirent name in bytes.
uint8_t size;
// Describes the type of the entry. Aligned with the
// POSIX d_type values. Use `DIRENT_TYPE_*` constants.
uint8_t type;
// Unterminated name of entry.
char name[0];
} __PACKED;
if (!result.ok()) {
cb(zx::error(result.status()));
return;
}
size_t index = 0;
auto& dirents = result->dirents;
std::vector<std::string> names;
while (index + sizeof(dirent) < dirents.count()) {
auto packed_entry = reinterpret_cast<const dirent*>(&result->dirents[index]);
size_t packed_entry_size = sizeof(dirent) + packed_entry->size;
if (index + packed_entry_size > dirents.count()) {
break;
}
names.emplace_back(packed_entry->name, packed_entry->size);
index += packed_entry_size;
}
cb(zx::ok(std::move(names)));
});
}
void ConnectToParentDevices(async_dispatcher_t* dispatcher, const driver::Namespace* ns,
ConnectCallback cb) {
std::vector<ParentDevice> devices;
auto result = ns->Connect<fuchsia_io::Directory>(
std::string("/svc/").append(fuchsia_driver_compat::Service::Name));
if (result.is_error()) {
cb(result.take_error());
return;
}
FindDirectoryEntries(
std::move(result.value()), dispatcher,
[ns, cb = std::move(cb)](zx::status<std::vector<std::string>> entries) mutable {
if (entries.is_error()) {
cb(entries.take_error());
return;
}
std::vector<ParentDevice> devices;
for (auto& name : entries.value()) {
if (name == ".") {
continue;
}
auto result = ns->Connect<fuchsia_driver_compat::Device>(
std::string("/svc/")
.append(fuchsia_driver_compat::Service::Name)
.append("/")
.append(name)
.append("/device"));
if (result.is_error()) {
cb(result.take_error());
return;
}
devices.push_back(ParentDevice{
.name = std::move(name),
.client = std::move(result.value()),
});
}
cb(zx::ok(std::move(devices)));
});
}
} // namespace compat