| // 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 |