1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <assert.h> 6#include <fcntl.h> 7#include <limits.h> 8#include <poll.h> 9#include <pthread.h> 10#include <stdatomic.h> 11#include <stddef.h> 12#include <stdlib.h> 13#include <string.h> 14#include <sys/ioctl.h> 15#include <threads.h> 16 17#include <zircon/assert.h> 18#include <zircon/device/device.h> 19#include <zircon/device/ioctl.h> 20#include <zircon/device/vfs.h> 21#include <zircon/processargs.h> 22#include <zircon/syscalls.h> 23 24#include <fuchsia/io/c/fidl.h> 25#include <lib/fdio/debug.h> 26#include <lib/fdio/io.h> 27#include <lib/fdio/namespace.h> 28#include <lib/fdio/remoteio.h> 29#include <lib/fdio/util.h> 30#include <lib/fdio/vfs.h> 31 32#include "private-fidl.h" 33#include "private-remoteio.h" 34 35#define ZXDEBUG 0 36 37// POLL_MASK and POLL_SHIFT intend to convert the lower five POLL events into 38// ZX_USER_SIGNALs and vice-versa. Other events need to be manually converted to 39// a zx_signals_t, if they are desired. 40#define POLL_SHIFT 24 41#define POLL_MASK 0x1F 42 43static_assert(ZX_USER_SIGNAL_0 == (1 << POLL_SHIFT), ""); 44static_assert((POLLIN << POLL_SHIFT) == DEVICE_SIGNAL_READABLE, ""); 45static_assert((POLLPRI << POLL_SHIFT) == DEVICE_SIGNAL_OOB, ""); 46static_assert((POLLOUT << POLL_SHIFT) == DEVICE_SIGNAL_WRITABLE, ""); 47static_assert((POLLERR << POLL_SHIFT) == DEVICE_SIGNAL_ERROR, ""); 48static_assert((POLLHUP << POLL_SHIFT) == DEVICE_SIGNAL_HANGUP, ""); 49 50zx_handle_t zxrio_handle(zxrio_t* rio) { 51 return rio->h; 52} 53 54// Acquire the additional handle from |info|. 55// 56// Returns |ZX_OK| if a handle was returned. 57// Returns |ZX_ERR_NOT_FOUND| if no handle can be returned. 58static zx_status_t zxrio_object_extract_handle(const zxrio_node_info_t* info, 59 zx_handle_t* out) { 60 switch (info->tag) { 61 case fuchsia_io_NodeInfoTag_file: 62 if (info->file.e != ZX_HANDLE_INVALID) { 63 *out = info->file.e; 64 return ZX_OK; 65 } 66 break; 67 case fuchsia_io_NodeInfoTag_pipe: 68 if (info->pipe.s != ZX_HANDLE_INVALID) { 69 *out = info->pipe.s; 70 return ZX_OK; 71 } 72 break; 73 case fuchsia_io_NodeInfoTag_vmofile: 74 if (info->vmofile.v != ZX_HANDLE_INVALID) { 75 *out = info->vmofile.v; 76 return ZX_OK; 77 } 78 break; 79 case fuchsia_io_NodeInfoTag_device: 80 if (info->device.e != ZX_HANDLE_INVALID) { 81 *out = info->device.e; 82 return ZX_OK; 83 } 84 break; 85 } 86 return ZX_ERR_NOT_FOUND; 87} 88 89static zx_status_t zxrio_close(fdio_t* io) { 90 zxrio_t* rio = (zxrio_t*)io; 91 92 zx_status_t r = fidl_close(rio); 93 zx_handle_t h = rio->h; 94 rio->h = ZX_HANDLE_INVALID; 95 zx_handle_close(h); 96 if (rio->event != ZX_HANDLE_INVALID) { 97 h = rio->event; 98 rio->event = ZX_HANDLE_INVALID; 99 zx_handle_close(h); 100 } 101 return r; 102} 103 104// Open an object without waiting for the response. 105// This function always consumes the cnxn handle 106// The svc handle is only used to send a message 107static zx_status_t zxrio_connect(zx_handle_t svc, zx_handle_t cnxn, 108 uint32_t op, uint32_t flags, uint32_t mode, 109 const char* name) { 110 size_t len = strlen(name); 111 if (len >= PATH_MAX) { 112 zx_handle_close(cnxn); 113 return ZX_ERR_BAD_PATH; 114 } 115 if (flags & ZX_FS_FLAG_DESCRIBE) { 116 zx_handle_close(cnxn); 117 return ZX_ERR_INVALID_ARGS; 118 } 119 120 zx_status_t r; 121 switch (op) { 122 case fuchsia_io_NodeCloneOrdinal: 123 r = fidl_clone_request(svc, cnxn, flags); 124 break; 125 case fuchsia_io_DirectoryOpenOrdinal: 126 r = fidl_open_request(svc, cnxn, flags, mode, name, len); 127 break; 128 default: 129 zx_handle_close(cnxn); 130 r = ZX_ERR_NOT_SUPPORTED; 131 } 132 return r; 133} 134 135static ssize_t zxrio_write(fdio_t* io, const void* data, size_t len) { 136 zxrio_t* rio = (zxrio_t*) io; 137 zx_status_t status = ZX_OK; 138 uint64_t count = 0; 139 uint64_t xfer; 140 while (len > 0) { 141 xfer = (len > FDIO_CHUNK_SIZE) ? FDIO_CHUNK_SIZE : len; 142 uint64_t actual = 0; 143 if ((status = fidl_write(rio, data, xfer, &actual)) != ZX_OK) { 144 return status; 145 } 146 count += actual; 147 data += actual; 148 len -= actual; 149 if (xfer != actual) { 150 break; 151 } 152 } 153 if (count == 0) { 154 return status; 155 } 156 return count; 157} 158 159static ssize_t zxrio_write_at(fdio_t* io, const void* data, size_t len, off_t offset) { 160 zxrio_t* rio = (zxrio_t*) io; 161 zx_status_t status = ZX_OK; 162 uint64_t count = 0; 163 uint64_t xfer; 164 while (len > 0) { 165 xfer = (len > FDIO_CHUNK_SIZE) ? FDIO_CHUNK_SIZE : len; 166 uint64_t actual = 0; 167 if ((status = fidl_writeat(rio, data, xfer, offset, &actual)) != ZX_OK) { 168 return status; 169 } 170 count += actual; 171 data += actual; 172 offset += actual; 173 len -= actual; 174 if (xfer != actual) { 175 break; 176 } 177 } 178 if (count == 0) { 179 return status; 180 } 181 return count; 182} 183 184static zx_status_t zxrio_get_attr(fdio_t* io, vnattr_t* out) { 185 zxrio_t* rio = (zxrio_t*)io; 186 return fidl_stat(rio, out); 187} 188 189static ssize_t zxrio_read(fdio_t* io, void* data, size_t len) { 190 zxrio_t* rio = (zxrio_t*) io; 191 zx_status_t status = ZX_OK; 192 uint64_t count = 0; 193 uint64_t xfer; 194 while (len > 0) { 195 xfer = (len > FDIO_CHUNK_SIZE) ? FDIO_CHUNK_SIZE : len; 196 uint64_t actual = 0; 197 if ((status = fidl_read(rio, data, xfer, &actual)) != ZX_OK) { 198 return status; 199 } 200 count += actual; 201 data += actual; 202 len -= actual; 203 if (xfer != actual) { 204 break; 205 } 206 } 207 if (count == 0) { 208 return status; 209 } 210 return count; 211} 212 213static ssize_t zxrio_read_at(fdio_t* io, void* data, size_t len, off_t offset) { 214 zxrio_t* rio = (zxrio_t*) io; 215 zx_status_t status = ZX_OK; 216 uint64_t count = 0; 217 uint64_t xfer; 218 while (len > 0) { 219 xfer = (len > FDIO_CHUNK_SIZE) ? FDIO_CHUNK_SIZE : len; 220 uint64_t actual = 0; 221 if ((status = fidl_readat(rio, data, xfer, offset, &actual)) != ZX_OK) { 222 return status; 223 } 224 offset += actual; 225 count += actual; 226 data += actual; 227 len -= actual; 228 if (xfer != actual) { 229 break; 230 } 231 } 232 if (count == 0) { 233 return status; 234 } 235 return count; 236} 237 238static off_t zxrio_seek(fdio_t* io, off_t offset, int whence) { 239 zxrio_t* rio = (zxrio_t*)io; 240 zx_status_t status = fidl_seek(rio, offset, whence, &offset); 241 if (status != ZX_OK) { 242 return status; 243 } 244 return offset; 245} 246 247static ssize_t zxrio_ioctl(fdio_t* io, uint32_t op, const void* in_buf, 248 size_t in_len, void* out_buf, size_t out_len) { 249 zxrio_t* rio = (zxrio_t*)io; 250 if (in_len > FDIO_IOCTL_MAX_INPUT || out_len > FDIO_CHUNK_SIZE) { 251 return ZX_ERR_INVALID_ARGS; 252 } 253 size_t actual; 254 zx_status_t status = fidl_ioctl(rio, op, in_buf, in_len, out_buf, out_len, &actual); 255 if (status != ZX_OK) { 256 return status; 257 } 258 return actual; 259} 260 261// Takes ownership of the optional |extra_handle|. 262// 263// Decodes the handle into |info|, if it exists and should 264// be decoded. 265static zx_status_t zxrio_decode_describe_handle(zxrio_describe_t* info, 266 zx_handle_t extra_handle) { 267 bool have_handle = (extra_handle != ZX_HANDLE_INVALID); 268 bool want_handle = false; 269 zx_handle_t* handle_target = NULL; 270 271 switch (info->extra.tag) { 272 // Case: No extra handles expected 273 case fuchsia_io_NodeInfoTag_service: 274 case fuchsia_io_NodeInfoTag_directory: 275 break; 276 // Case: Extra handles optional 277 case fuchsia_io_NodeInfoTag_file: 278 handle_target = &info->extra.file.e; 279 goto handle_optional; 280 case fuchsia_io_NodeInfoTag_device: 281 handle_target = &info->extra.device.e; 282 goto handle_optional; 283handle_optional: 284 want_handle = *handle_target == FIDL_HANDLE_PRESENT; 285 break; 286 // Case: Extra handles required 287 case fuchsia_io_NodeInfoTag_pipe: 288 handle_target = &info->extra.pipe.s; 289 goto handle_required; 290 case fuchsia_io_NodeInfoTag_vmofile: 291 handle_target = &info->extra.vmofile.v; 292 goto handle_required; 293handle_required: 294 want_handle = *handle_target == FIDL_HANDLE_PRESENT; 295 if (!want_handle) { 296 goto fail; 297 } 298 break; 299 default: 300 printf("Unexpected protocol type opening connection\n"); 301 goto fail; 302 } 303 304 if (have_handle != want_handle) { 305 goto fail; 306 } 307 if (have_handle) { 308 *handle_target = extra_handle; 309 } 310 return ZX_OK; 311 312fail: 313 if (have_handle) { 314 zx_handle_close(extra_handle); 315 } 316 return ZX_ERR_IO; 317} 318 319// Wait/Read from a new client connection, with the expectation of 320// acquiring an Open response. 321// 322// Shared implementation between RemoteIO and FIDL, since the response 323// message is aligned. 324// 325// Does not close |h|, even on error. 326static zx_status_t zxrio_process_open_response(zx_handle_t h, zxrio_describe_t* info) { 327 zx_object_wait_one(h, ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, 328 ZX_TIME_INFINITE, NULL); 329 330 // Attempt to read the description from open 331 uint32_t dsize = sizeof(*info); 332 zx_handle_t extra_handle = ZX_HANDLE_INVALID; 333 uint32_t actual_handles; 334 zx_status_t r = zx_channel_read(h, 0, info, &extra_handle, dsize, 1, &dsize, 335 &actual_handles); 336 if (r != ZX_OK) { 337 return r; 338 } 339 if (dsize < ZXRIO_DESCRIBE_HDR_SZ || info->hdr.ordinal != fuchsia_io_NodeOnOpenOrdinal) { 340 r = ZX_ERR_IO; 341 } else { 342 r = info->status; 343 } 344 345 if (dsize != sizeof(zxrio_describe_t)) { 346 r = (r != ZX_OK) ? r : ZX_ERR_IO; 347 } 348 349 if (r != ZX_OK) { 350 if (extra_handle != ZX_HANDLE_INVALID) { 351 zx_handle_close(extra_handle); 352 } 353 return r; 354 } 355 356 // Confirm that the objects "zxrio_describe_t" and "fuchsia_io_NodeOnOpenEvent" 357 // are aligned enough to be compatible. 358 // 359 // This is somewhat complicated by the fact that the "fuchsia_io_NodeOnOpenEvent" 360 // object has an optional "fuchsia_io_NodeInfo" secondary which exists immediately 361 // following the struct. 362 static_assert(__builtin_offsetof(zxrio_describe_t, extra) == 363 FIDL_ALIGN(sizeof(fuchsia_io_NodeOnOpenEvent)), 364 "RIO Description message doesn't align with FIDL response secondary"); 365 static_assert(sizeof(zxrio_node_info_t) == sizeof(fuchsia_io_NodeInfo), 366 "RIO Node Info doesn't align with FIDL object info"); 367 static_assert(__builtin_offsetof(zxrio_node_info_t, file.e) == 368 __builtin_offsetof(fuchsia_io_NodeInfo, file.event), "Unaligned File"); 369 static_assert(__builtin_offsetof(zxrio_node_info_t, pipe.s) == 370 __builtin_offsetof(fuchsia_io_NodeInfo, pipe.socket), "Unaligned Pipe"); 371 static_assert(__builtin_offsetof(zxrio_node_info_t, vmofile.v) == 372 __builtin_offsetof(fuchsia_io_NodeInfo, vmofile.vmo), "Unaligned Vmofile"); 373 static_assert(__builtin_offsetof(zxrio_node_info_t, device.e) == 374 __builtin_offsetof(fuchsia_io_NodeInfo, device.event), "Unaligned Device"); 375 // Connection::NodeDescribe also relies on these static_asserts. 376 // fidl_describe also relies on these static_asserts. 377 378 return zxrio_decode_describe_handle(info, extra_handle); 379} 380 381__EXPORT 382zx_status_t fdio_service_connect(const char* svcpath, zx_handle_t h) { 383 if (svcpath == NULL) { 384 zx_handle_close(h); 385 return ZX_ERR_INVALID_ARGS; 386 } 387 // Otherwise attempt to connect through the root namespace 388 if (fdio_root_ns != NULL) { 389 return fdio_ns_connect(fdio_root_ns, svcpath, 390 ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, h); 391 } 392 // Otherwise we fail 393 zx_handle_close(h); 394 return ZX_ERR_NOT_FOUND; 395} 396 397__EXPORT 398zx_status_t fdio_service_connect_at(zx_handle_t dir, const char* path, zx_handle_t h) { 399 if (path == NULL) { 400 zx_handle_close(h); 401 return ZX_ERR_INVALID_ARGS; 402 } 403 if (dir == ZX_HANDLE_INVALID) { 404 zx_handle_close(h); 405 return ZX_ERR_UNAVAILABLE; 406 } 407 return zxrio_connect(dir, h, fuchsia_io_DirectoryOpenOrdinal, ZX_FS_RIGHT_READABLE | 408 ZX_FS_RIGHT_WRITABLE, 0755, path); 409} 410 411__EXPORT 412zx_status_t fdio_open_at(zx_handle_t dir, const char* path, uint32_t flags, zx_handle_t h) { 413 if (path == NULL) { 414 zx_handle_close(h); 415 return ZX_ERR_INVALID_ARGS; 416 } 417 if (dir == ZX_HANDLE_INVALID) { 418 zx_handle_close(h); 419 return ZX_ERR_UNAVAILABLE; 420 } 421 return zxrio_connect(dir, h, fuchsia_io_DirectoryOpenOrdinal, flags, 0755, path); 422} 423 424__EXPORT 425zx_handle_t fdio_service_clone(zx_handle_t svc) { 426 zx_handle_t cli, srv; 427 zx_status_t r; 428 if (svc == ZX_HANDLE_INVALID) { 429 return ZX_HANDLE_INVALID; 430 } 431 if ((r = zx_channel_create(0, &cli, &srv)) < 0) { 432 return ZX_HANDLE_INVALID; 433 } 434 if ((r = zxrio_connect(svc, srv, fuchsia_io_NodeCloneOrdinal, ZX_FS_RIGHT_READABLE | 435 ZX_FS_RIGHT_WRITABLE, 0755, "")) < 0) { 436 zx_handle_close(cli); 437 return ZX_HANDLE_INVALID; 438 } 439 return cli; 440} 441 442__EXPORT 443zx_status_t fdio_service_clone_to(zx_handle_t svc, zx_handle_t srv) { 444 if (srv == ZX_HANDLE_INVALID) { 445 return ZX_ERR_INVALID_ARGS; 446 } 447 if (svc == ZX_HANDLE_INVALID) { 448 zx_handle_close(srv); 449 return ZX_ERR_INVALID_ARGS; 450 } 451 return zxrio_connect(svc, srv, fuchsia_io_NodeCloneOrdinal, ZX_FS_RIGHT_READABLE | 452 ZX_FS_RIGHT_WRITABLE, 0755, ""); 453} 454 455zx_status_t fdio_acquire_socket(zx_handle_t socket, fdio_t** out_io) { 456 zx_info_socket_t info; 457 memset(&info, 0, sizeof(info)); 458 zx_status_t status = zx_object_get_info(socket, ZX_INFO_SOCKET, &info, sizeof(info), NULL, NULL); 459 if (status != ZX_OK) { 460 zx_handle_close(socket); 461 return status; 462 } 463 fdio_t* io = NULL; 464 if ((info.options & ZX_SOCKET_HAS_CONTROL) != 0) { 465 // If the socket has a control plane, then the socket is either 466 // a stream or a datagram socket. 467 if ((info.options & ZX_SOCKET_DATAGRAM) != 0) { 468 io = fdio_socket_create_datagram(socket, IOFLAG_SOCKET_CONNECTED); 469 } else { 470 io = fdio_socket_create_stream(socket, IOFLAG_SOCKET_CONNECTED); 471 } 472 } else { 473 // Without a control plane, the socket is a pipe. 474 io = fdio_pipe_create(socket); 475 } 476 if (!io) { 477 return ZX_ERR_NO_RESOURCES; 478 } 479 *out_io = io; 480 return ZX_OK; 481} 482 483// Create a fdio (if possible) from handles and info. 484// 485// The Control channel is provided in |handle|, and auxillary 486// handles may be provided in the |info| object. 487// 488// This function always takes control of all handles. 489// They are transferred into the |out| object on success, 490// or closed on failure. 491static zx_status_t fdio_from_handles(zx_handle_t handle, zxrio_node_info_t* info, 492 fdio_t** out) { 493 // All failure cases which discard handles set r and break 494 // to the end. All other cases in which handle ownership is moved 495 // on return locally. 496 zx_status_t r; 497 fdio_t* io; 498 switch (info->tag) { 499 case fuchsia_io_NodeInfoTag_directory: 500 case fuchsia_io_NodeInfoTag_service: 501 if (handle == ZX_HANDLE_INVALID) { 502 r = ZX_ERR_INVALID_ARGS; 503 break; 504 } 505 io = fdio_remote_create(handle, 0); 506 xprintf("rio (%x,%x) -> %p\n", handle, 0, io); 507 if (io == NULL) { 508 return ZX_ERR_NO_RESOURCES; 509 } 510 *out = io; 511 return ZX_OK; 512 case fuchsia_io_NodeInfoTag_file: 513 if (info->file.e == ZX_HANDLE_INVALID) { 514 io = fdio_remote_create(handle, 0); 515 xprintf("rio (%x,%x) -> %p\n", handle, 0, io); 516 } else { 517 io = fdio_remote_create(handle, info->file.e); 518 xprintf("rio (%x,%x) -> %p\n", handle, info->file.e, io); 519 } 520 if (io == NULL) { 521 return ZX_ERR_NO_RESOURCES; 522 } 523 *out = io; 524 return ZX_OK; 525 case fuchsia_io_NodeInfoTag_device: 526 if (info->device.e == ZX_HANDLE_INVALID) { 527 io = fdio_remote_create(handle, 0); 528 xprintf("rio (%x,%x) -> %p\n", handle, 0, io); 529 } else { 530 io = fdio_remote_create(handle, info->device.e); 531 xprintf("rio (%x,%x) -> %p\n", handle, info->device.e, io); 532 } 533 if (io == NULL) { 534 return ZX_ERR_NO_RESOURCES; 535 } 536 *out = io; 537 return ZX_OK; 538 case fuchsia_io_NodeInfoTag_vmofile: { 539 if (info->vmofile.v == ZX_HANDLE_INVALID) { 540 r = ZX_ERR_INVALID_ARGS; 541 break; 542 } 543 *out = fdio_vmofile_create(handle, info->vmofile.v, info->vmofile.offset, 544 info->vmofile.length); 545 if (*out == NULL) { 546 return ZX_ERR_NO_RESOURCES; 547 } 548 return ZX_OK; 549 } 550 case fuchsia_io_NodeInfoTag_pipe: { 551 if (info->pipe.s == ZX_HANDLE_INVALID) { 552 r = ZX_ERR_INVALID_ARGS; 553 break; 554 } 555 zx_handle_close(handle); 556 return fdio_acquire_socket(info->pipe.s, out); 557 } 558 default: 559 printf("fdio_from_handles: Not supported\n"); 560 r = ZX_ERR_NOT_SUPPORTED; 561 break; 562 } 563 zx_handle_t extra; 564 if (zxrio_object_extract_handle(info, &extra) == ZX_OK) { 565 zx_handle_close(extra); 566 } 567 zx_handle_close(handle); 568 return r; 569} 570 571__EXPORT 572zx_status_t fdio_create_fd(zx_handle_t* handles, uint32_t* types, size_t hcount, 573 int* fd_out) { 574 fdio_t* io; 575 zx_status_t r; 576 int fd; 577 zxrio_node_info_t info; 578 579 // Pack additional handles into |info|, if possible. 580 switch (PA_HND_TYPE(types[0])) { 581 case PA_FDIO_REMOTE: 582 switch (hcount) { 583 case 1: 584 io = fdio_remote_create(handles[0], 0); 585 goto bind; 586 case 2: 587 io = fdio_remote_create(handles[0], handles[1]); 588 goto bind; 589 default: 590 r = ZX_ERR_INVALID_ARGS; 591 goto fail; 592 } 593 case PA_FDIO_SOCKET: 594 info.tag = fuchsia_io_NodeInfoTag_pipe; 595 // Expected: Single socket handle 596 if (hcount != 1) { 597 r = ZX_ERR_INVALID_ARGS; 598 goto fail; 599 } 600 info.pipe.s = handles[0]; 601 break; 602 default: 603 r = ZX_ERR_IO; 604 goto fail; 605 } 606 607 if ((r = fdio_from_handles(ZX_HANDLE_INVALID, &info, &io)) != ZX_OK) { 608 return r; 609 } 610 611bind: 612 fd = fdio_bind_to_fd(io, -1, 0); 613 if (fd < 0) { 614 fdio_close(io); 615 fdio_release(io); 616 return ZX_ERR_BAD_STATE; 617 } 618 619 *fd_out = fd; 620 return ZX_OK; 621fail: 622 zx_handle_close_many(handles, hcount); 623 return r; 624} 625 626// Synchronously (non-pipelined) open an object 627// The svc handle is only used to send a message 628static zx_status_t zxrio_sync_open_connection(zx_handle_t svc, uint32_t op, 629 uint32_t flags, uint32_t mode, 630 const char* path, size_t pathlen, 631 zxrio_describe_t* info, zx_handle_t* out) { 632 if (!(flags & ZX_FS_FLAG_DESCRIBE)) { 633 return ZX_ERR_INVALID_ARGS; 634 } 635 636 zx_status_t r; 637 zx_handle_t h; 638 zx_handle_t cnxn; 639 if ((r = zx_channel_create(0, &h, &cnxn)) != ZX_OK) { 640 return r; 641 } 642 643 switch (op) { 644 case fuchsia_io_NodeCloneOrdinal: 645 r = fidl_clone_request(svc, cnxn, flags); 646 break; 647 case fuchsia_io_DirectoryOpenOrdinal: 648 r = fidl_open_request(svc, cnxn, flags, mode, path, pathlen); 649 break; 650 default: 651 zx_handle_close(cnxn); 652 r = ZX_ERR_NOT_SUPPORTED; 653 } 654 655 if (r != ZX_OK) { 656 zx_handle_close(h); 657 return r; 658 } 659 660 if ((r = zxrio_process_open_response(h, info)) != ZX_OK) { 661 zx_handle_close(h); 662 return r; 663 } 664 *out = h; 665 return ZX_OK; 666} 667 668// Acquires a new connection to an object. 669// 670// Returns a description of the opened object in |info|, and 671// the control channel to the object in |out|. 672// 673// |info| may contain an additional handle. 674static zx_status_t zxrio_getobject(zx_handle_t rio_h, uint32_t op, const char* name, 675 uint32_t flags, uint32_t mode, 676 zxrio_describe_t* info, zx_handle_t* out) { 677 if (name == NULL) { 678 return ZX_ERR_INVALID_ARGS; 679 } 680 681 size_t len = strlen(name); 682 if (len >= PATH_MAX) { 683 return ZX_ERR_BAD_PATH; 684 } 685 686 if (flags & ZX_FS_FLAG_DESCRIBE) { 687 return zxrio_sync_open_connection(rio_h, op, flags, mode, name, len, info, out); 688 } else { 689 zx_handle_t h0, h1; 690 zx_status_t r; 691 if ((r = zx_channel_create(0, &h0, &h1)) < 0) { 692 return r; 693 } 694 if ((r = zxrio_connect(rio_h, h1, op, flags, mode, name)) < 0) { 695 zx_handle_close(h0); 696 return r; 697 } 698 // fake up a reply message since pipelined opens don't generate one 699 info->status = ZX_OK; 700 info->extra.tag = fuchsia_io_NodeInfoTag_service; 701 *out = h0; 702 return ZX_OK; 703 } 704} 705 706zx_status_t zxrio_open_handle(zx_handle_t h, const char* path, uint32_t flags, 707 uint32_t mode, fdio_t** out) { 708 zx_handle_t control_channel; 709 zxrio_describe_t info; 710 zx_status_t r = zxrio_getobject(h, fuchsia_io_DirectoryOpenOrdinal, path, flags, mode, &info, &control_channel); 711 if (r < 0) { 712 return r; 713 } 714 return fdio_from_handles(control_channel, &info.extra, out); 715} 716 717static zx_status_t zxrio_open(fdio_t* io, const char* path, uint32_t flags, uint32_t mode, fdio_t** out) { 718 zxrio_t* rio = (void*)io; 719 return zxrio_open_handle(rio->h, path, flags, mode, out); 720} 721 722static zx_status_t zxrio_clone(fdio_t* io, zx_handle_t* handles, uint32_t* types) { 723 zxrio_t* rio = (void*)io; 724 zx_handle_t h; 725 zxrio_describe_t info; 726 zx_status_t r = zxrio_getobject(rio->h, fuchsia_io_NodeCloneOrdinal, "", 0, 0, &info, &h); 727 if (r < 0) { 728 return r; 729 } 730 handles[0] = h; 731 types[0] = PA_FDIO_REMOTE; 732 return 1; 733} 734 735static zx_status_t zxrio_unwrap(fdio_t* io, zx_handle_t* handles, uint32_t* types) { 736 zxrio_t* rio = (void*)io; 737 LOG(1, "fdio: zxrio_unwrap(%p,...)\n"); 738 handles[0] = rio->h; 739 types[0] = PA_FDIO_REMOTE; 740 if (rio->event != ZX_HANDLE_INVALID) { 741 zx_handle_close(rio->event); 742 rio->event = ZX_HANDLE_INVALID; 743 } 744 return 1; 745} 746 747static void zxrio_wait_begin(fdio_t* io, uint32_t events, zx_handle_t* handle, zx_signals_t* _signals) { 748 zxrio_t* rio = (void*)io; 749 *handle = rio->event; 750 751 zx_signals_t signals = 0; 752 // Manually add signals that don't fit within POLL_MASK 753 if (events & POLLRDHUP) { 754 signals |= ZX_CHANNEL_PEER_CLOSED; 755 } 756 757 // POLLERR is always detected 758 *_signals = (((POLLERR | events) & POLL_MASK) << POLL_SHIFT) | signals; 759} 760 761static void zxrio_wait_end(fdio_t* io, zx_signals_t signals, uint32_t* _events) { 762 // Manually add events that don't fit within POLL_MASK 763 uint32_t events = 0; 764 if (signals & ZX_CHANNEL_PEER_CLOSED) { 765 events |= POLLRDHUP; 766 } 767 *_events = ((signals >> POLL_SHIFT) & POLL_MASK) | events; 768} 769 770static zx_status_t zxrio_get_vmo(fdio_t* io, int flags, zx_handle_t* out) { 771 zx_handle_t vmo; 772 zxrio_t* rio = (zxrio_t*)io; 773 zx_status_t r = fidl_getvmo(rio, flags, &vmo); 774 if (r != ZX_OK) { 775 return r; 776 } 777 *out = vmo; 778 return ZX_OK; 779} 780 781static zx_status_t zxrio_get_token(fdio_t* io, zx_handle_t* out) { 782 zxrio_t* rio = (zxrio_t*)io; 783 return fidl_gettoken(rio, out); 784} 785 786static zx_status_t zxrio_set_attr(fdio_t* io, const vnattr_t* attr) { 787 zxrio_t* rio = (zxrio_t*)io; 788 return fidl_setattr(rio, attr); 789} 790 791static zx_status_t zxrio_sync(fdio_t* io) { 792 zxrio_t* rio = (zxrio_t*)io; 793 return fidl_sync(rio); 794} 795 796static zx_status_t zxrio_readdir(fdio_t* io, void* ptr, size_t max, size_t* actual) { 797 zxrio_t* rio = (zxrio_t*)io; 798 return fidl_readdirents(rio, ptr, max, actual); 799} 800 801static zx_status_t zxrio_rewind(fdio_t* io) { 802 zxrio_t* rio = (zxrio_t*)io; 803 return fidl_rewind(rio); 804} 805 806static zx_status_t zxrio_unlink(fdio_t* io, const char* path, size_t len) { 807 zxrio_t* rio = (zxrio_t*)io; 808 return fidl_unlink(rio, path, len); 809} 810 811static zx_status_t zxrio_truncate(fdio_t* io, off_t off) { 812 zxrio_t* rio = (zxrio_t*)io; 813 return fidl_truncate(rio, off); 814} 815 816static zx_status_t zxrio_rename(fdio_t* io, const char* src, size_t srclen, 817 zx_handle_t dst_token, const char* dst, size_t dstlen) { 818 zxrio_t* rio = (zxrio_t*)io; 819 return fidl_rename(rio, src, srclen, dst_token, dst, dstlen); 820} 821 822static zx_status_t zxrio_link(fdio_t* io, const char* src, size_t srclen, 823 zx_handle_t dst_token, const char* dst, size_t dstlen) { 824 zxrio_t* rio = (zxrio_t*)io; 825 return fidl_link(rio, src, srclen, dst_token, dst, dstlen); 826} 827 828static zx_status_t zxrio_get_flags(fdio_t* io, uint32_t* out_flags) { 829 zxrio_t* rio = (zxrio_t*)io; 830 return fidl_getflags(rio, out_flags); 831} 832 833static zx_status_t zxrio_set_flags(fdio_t* io, uint32_t flags) { 834 zxrio_t* rio = (zxrio_t*)io; 835 return fidl_setflags(rio, flags); 836} 837 838fdio_ops_t zx_remote_ops = { 839 .read = zxrio_read, 840 .read_at = zxrio_read_at, 841 .write = zxrio_write, 842 .write_at = zxrio_write_at, 843 .seek = zxrio_seek, 844 .misc = fdio_default_misc, 845 .close = zxrio_close, 846 .open = zxrio_open, 847 .clone = zxrio_clone, 848 .ioctl = zxrio_ioctl, 849 .wait_begin = zxrio_wait_begin, 850 .wait_end = zxrio_wait_end, 851 .unwrap = zxrio_unwrap, 852 .posix_ioctl = fdio_default_posix_ioctl, 853 .get_vmo = zxrio_get_vmo, 854 .get_token = zxrio_get_token, 855 .get_attr = zxrio_get_attr, 856 .set_attr = zxrio_set_attr, 857 .sync = zxrio_sync, 858 .readdir = zxrio_readdir, 859 .rewind = zxrio_rewind, 860 .unlink = zxrio_unlink, 861 .truncate = zxrio_truncate, 862 .rename = zxrio_rename, 863 .link = zxrio_link, 864 .get_flags = zxrio_get_flags, 865 .set_flags = zxrio_set_flags, 866 .recvfrom = fdio_default_recvfrom, 867 .sendto = fdio_default_sendto, 868 .recvmsg = fdio_default_recvmsg, 869 .sendmsg = fdio_default_sendmsg, 870 .shutdown = fdio_default_shutdown, 871}; 872 873__EXPORT 874fdio_t* fdio_remote_create(zx_handle_t h, zx_handle_t event) { 875 zxrio_t* rio = fdio_alloc(sizeof(*rio)); 876 if (rio == NULL) { 877 zx_handle_close(h); 878 zx_handle_close(event); 879 return NULL; 880 } 881 rio->io.ops = &zx_remote_ops; 882 rio->io.magic = FDIO_MAGIC; 883 atomic_init(&rio->io.refcount, 1); 884 rio->h = h; 885 rio->event = event; 886 return &rio->io; 887} 888