[fdio] Deprecate fdio_ns_connect

This function is inconsistently named; service connection functions do
not accept flags.

Replaced with fdio_ns_open and fdio_ns_service_connect.

Move shared logic that disallows fuchsia_io/OpenFlags.DESCRIBE so it is
specific to fdio_ns_connect.

Change-Id: I5e45d8382c0b433c95df58390a87ac54faf383c1
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/693798
API-Review: Adam Barth <abarth@google.com>
Fuchsia-Auto-Submit: Tamir Duberstein <tamird@google.com>
Commit-Queue: Auto-Submit <auto-submit@fuchsia-infra.iam.gserviceaccount.com>
Reviewed-by: Adam Barth <abarth@google.com>
diff --git a/sdk/lib/driver2/namespace.cc b/sdk/lib/driver2/namespace.cc
index 92795b7..dee88c3 100644
--- a/sdk/lib/driver2/namespace.cc
+++ b/sdk/lib/driver2/namespace.cc
@@ -57,8 +57,10 @@
 
 zx::status<> Namespace::Connect(std::string_view path, zx::channel server_end,
                                 fuchsia_io::wire::OpenFlags flags) const {
+  // TODO(https://fxbug.dev/103308): should this call fdio_ns_service_connect
+  // instead? The flags argument would need to be removed.
   zx_status_t status =
-      fdio_ns_connect(ns_, path.data(), static_cast<uint32_t>(flags), server_end.release());
+      fdio_ns_open(ns_, path.data(), static_cast<uint32_t>(flags), server_end.release());
   return zx::make_status(status);
 }
 
diff --git a/sdk/lib/fdio/directory.cc b/sdk/lib/fdio/directory.cc
index aa71816..683fc37 100644
--- a/sdk/lib/fdio/directory.cc
+++ b/sdk/lib/fdio/directory.cc
@@ -14,20 +14,23 @@
 
 namespace fio = fuchsia_io;
 
+// TODO(https://fxbug.dev/101092): Shrink this to 0.
+constexpr uint32_t kServiceFlags = static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable |
+                                                         fio::wire::OpenFlags::kRightWritable);
+
 __EXPORT
 zx_status_t fdio_service_connect(const char* path, zx_handle_t h) {
-  return fdio_open(path,
-                   static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable |
-                                         fio::wire::OpenFlags::kRightWritable),
-                   h);
+  zx::handle handle{h};
+  fdio_ns_t* ns;
+  if (zx_status_t status = fdio_ns_get_installed(&ns); status != ZX_OK) {
+    return status;
+  }
+  return fdio_ns_open(ns, path, kServiceFlags, handle.release());
 }
 
 __EXPORT
 zx_status_t fdio_service_connect_at(zx_handle_t dir, const char* path, zx_handle_t h) {
-  return fdio_open_at(dir, path,
-                      static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable |
-                                            fio::wire::OpenFlags::kRightWritable),
-                      h);
+  return fdio_open_at(dir, path, kServiceFlags, h);
 }
 
 __EXPORT
@@ -56,18 +59,12 @@
 
 __EXPORT
 zx_status_t fdio_open(const char* path, uint32_t flags, zx_handle_t request) {
-  auto handle = zx::handle(request);
-  // TODO: fdio_validate_path?
-  if (path == nullptr) {
-    return ZX_ERR_INVALID_ARGS;
-  }
-  // Otherwise attempt to connect through the root namespace
+  zx::handle handle{request};
   fdio_ns_t* ns;
-  zx_status_t status = fdio_ns_get_installed(&ns);
-  if (status != ZX_OK) {
+  if (zx_status_t status = fdio_ns_get_installed(&ns); status != ZX_OK) {
     return status;
   }
-  return fdio_ns_connect(ns, path, flags, handle.release());
+  return fdio_ns_open(ns, path, flags, handle.release());
 }
 
 // We need to select some value to pass as the mode when calling Directory.Open. We use this value
@@ -84,10 +81,6 @@
     return ZX_ERR_UNAVAILABLE;
   }
 
-  if (flags & fio::wire::OpenFlags::kDescribe) {
-    return ZX_ERR_INVALID_ARGS;
-  }
-
   return fidl::WireCall(directory)
       ->Open(flags, kArbitraryMode, fidl::StringView::FromExternal(path), std::move(request))
       .status();
diff --git a/sdk/lib/fdio/fdio.api b/sdk/lib/fdio/fdio.api
index 7192332..c5f8463 100644
--- a/sdk/lib/fdio/fdio.api
+++ b/sdk/lib/fdio/fdio.api
@@ -1,10 +1,10 @@
 {
-  "pkg/fdio/include/lib/fdio/directory.h": "9d3a641d228482f0dfb343f0ca8eeb8c",
+  "pkg/fdio/include/lib/fdio/directory.h": "a65310f1923370f34f071cd476ecd793",
   "pkg/fdio/include/lib/fdio/fd.h": "3066f7f319c7f8b6cd57f5a96f4ff6e5",
   "pkg/fdio/include/lib/fdio/fdio.h": "fb3fab45bec9b946e1d72b3a01cd6426",
   "pkg/fdio/include/lib/fdio/io.h": "af6073b8ad02cf65480922eb9f1b8275",
   "pkg/fdio/include/lib/fdio/limits.h": "9b99b72bd188543dba96528bf5797ca8",
-  "pkg/fdio/include/lib/fdio/namespace.h": "6cddc7c1c378ca5658608e64be5a2e9c",
+  "pkg/fdio/include/lib/fdio/namespace.h": "ed2c65b633279a677f13cfd09d760d18",
   "pkg/fdio/include/lib/fdio/private.h": "bfab891792785c49734bf3305006de8a",
   "pkg/fdio/include/lib/fdio/spawn.h": "88256edf331027ba491a29e66aff12cd",
   "pkg/fdio/include/lib/fdio/unsafe.h": "978c3ec5ca1f61d70a2639241611cd4b",
diff --git a/sdk/lib/fdio/fdio.ifs b/sdk/lib/fdio/fdio.ifs
index 5b925f1..4830fb7 100644
--- a/sdk/lib/fdio/fdio.ifs
+++ b/sdk/lib/fdio/fdio.ifs
@@ -58,7 +58,9 @@
   - { Name: fdio_ns_free_flat_ns, Type: Func }
   - { Name: fdio_ns_get_installed, Type: Func }
   - { Name: fdio_ns_is_bound, Type: Func }
+  - { Name: fdio_ns_open, Type: Func }
   - { Name: fdio_ns_opendir, Type: Func }
+  - { Name: fdio_ns_service_connect, Type: Func }
   - { Name: fdio_ns_unbind, Type: Func }
   - { Name: fdio_null_create, Type: Func }
   - { Name: fdio_open, Type: Func }
diff --git a/sdk/lib/fdio/fdio.ld b/sdk/lib/fdio/fdio.ld
index d6bc2cb..646cd6d 100644
--- a/sdk/lib/fdio/fdio.ld
+++ b/sdk/lib/fdio/fdio.ld
@@ -56,7 +56,9 @@
 		fdio_ns_free_flat_ns;
 		fdio_ns_get_installed;
 		fdio_ns_is_bound;
+		fdio_ns_open;
 		fdio_ns_opendir;
+		fdio_ns_service_connect;
 		fdio_ns_unbind;
 		fdio_null_create;
 		fdio_open;
diff --git a/sdk/lib/fdio/include/lib/fdio/directory.h b/sdk/lib/fdio/include/lib/fdio/directory.h
index 6055a82..66dd7e9 100644
--- a/sdk/lib/fdio/include/lib/fdio/directory.h
+++ b/sdk/lib/fdio/include/lib/fdio/directory.h
@@ -16,37 +16,19 @@
 
 __BEGIN_CDECLS
 
-// Connects to a service at the given |path|.
-//
-// The |path| is looked up in the namespace for the current process. If found in
-// the namespace, the object at the path is opened, passing the |request| to
-// the remote party.
-//
-// Upon success, the |request| is handed off to the remote party. The operation
-// completes asynchronously, which means a ZX_OK result does not ensure that the
-// requested service actually exists.
+// Connects to a service at |path| relative to the root of the namespace for the
+// current process asynchronously.
 //
 // |request| must be a channel.
 //
 // Always consumes |request|.
 //
-// # Errors
-//
-// ZX_ERR_INVALID_ARGS: |path| is invalid.
-//
-// ZX_ERR_NOT_FOUND: A prefix of |path| cannot be found in the namespace for the
-// current process.
-//
-// ZX_ERR_NOT_SUPPORTED: The requested |path| was found in the namespace for the
-// current process but the namespace entry does not support connecting to
-// services.
-//
-// ZX_ERR_ACCESS_DENIED: The namespace entry has insufficient rights to connect
-// to services.
+// See |fdio_ns_service_connect| for details.
 zx_status_t fdio_service_connect(const char* path, ZX_HANDLE_RELEASE zx_handle_t request)
     ZX_AVAILABLE_SINCE(1);
 
-// Connects to a service at the given |path| relative to the given |directory|.
+// Connects to a service at the given |path| relative to the given |directory|
+// asynchronously.
 //
 // Upon success, the |request| is handed off to the remote party. The operation
 // completes asynchronously, which means a ZX_OK result does not ensure that the
@@ -62,9 +44,6 @@
 // # Errors
 //
 // ZX_ERR_INVALID_ARGS: |directory| or |path| is invalid.
-//
-// ZX_ERR_ACCESS_DENIED: |directory| has insufficient rights to connect to
-// services.
 zx_status_t fdio_service_connect_at(zx_handle_t directory, const char* path,
                                     ZX_HANDLE_RELEASE zx_handle_t request) ZX_AVAILABLE_SINCE(1);
 
@@ -72,49 +51,60 @@
 zx_status_t fdio_service_connect_by_name(const char* name, ZX_HANDLE_RELEASE zx_handle_t request)
     ZX_AVAILABLE_SINCE(1);
 
-// Opens the remote object at the given |path| relative to the root of the namespace with the given
-// |flags| asynchronously.
+// Opens an object at |path| relative to the root of the namespace for the
+// current process with |flags| asynchronously.
 //
 // |flags| is a |fuchsia.io/OpenFlags|.
 //
 // Always consumes |request|.
 //
-// See |fdio_service_connect| for details.
+// See |fdio_ns_open| for details.
 zx_status_t fdio_open(const char* path, uint32_t flags, ZX_HANDLE_RELEASE zx_handle_t request)
     ZX_AVAILABLE_SINCE(1);
 
-// Opens the remote object at the given |path| relative to the given |directory| with the given
-// |flags| asynchronously.
+// Opens an object at |path| relative to |directory| with |flags| asynchronously.
 //
-// |flags| is a |fuchsia.io/OpenFlags|.
+// Upon success, |request| is handed off to the remote party. The operation
+// completes asynchronously, which means a ZX_OK result does not ensure that the
+// requested service actually exists.
+//
+// |directory| must be a channel that implements the |fuchsia.io/Directory|
+// protocol.
+//
+// |request| must be a channel.
 //
 // Always consumes |request|.
 //
-// See |fdio_service_connect_at| for details.
+// # Errors
+//
+// ZX_ERR_INVALID_ARGS: |directory| or |path| is invalid.
 zx_status_t fdio_open_at(zx_handle_t directory, const char* path, uint32_t flags,
                          ZX_HANDLE_RELEASE zx_handle_t request) ZX_AVAILABLE_SINCE(1);
 
-// Opens the remote object at the given |path| relative to the root of the namespace with the given
-// |flags| synchronously, and on success, binds that channel to a file descriptor, returned via
-// |out_fd|.
+// Opens an object at |path| relative to the root of the namespace for the
+// current process with |flags| synchronously, and on success, binds that
+// channel to a file descriptor, returned via |out_fd|.
 //
-// Note that unlike fdio_open, this function is synchronous. This is because it produces a file
-// descriptor, which requires synchronously waiting for the open to complete.
+// Note that unlike fdio_open, this function is synchronous. This is because it
+// produces a file descriptor, which requires synchronously waiting for the open
+// to complete.
 //
 // |flags| is a |fuchsia.io/OpenFlags|.
 //
-// See |fdio_service_connect| for details.
+// See |fdio_open| for details.
 zx_status_t fdio_open_fd(const char* path, uint32_t flags, int* out_fd) ZX_AVAILABLE_SINCE(1);
 
-// Opens the remote object at the given |path| relative to the given |dir_fd| with the given |flags|
-// synchronously, and on success, binds that channel to a file descriptor, returned via |out_fd|.
+// Opens an object at |path| relative to |dir_fd| with |flags| synchronously,
+// and on success, binds that channel to a file descriptor, returned via
+// |out_fd|.
 //
-// Note that unlike fdio_open, this function is synchronous. This is because it produces a file
-// descriptor, which requires synchronously waiting for the open to complete.
+// Note that unlike fdio_open, this function is synchronous. This is because it
+// produces a file descriptor, which requires synchronously waiting for the open
+// to complete.
 //
 // |flags| is a |fuchsia.io/OpenFlags|.
 //
-// See |fdio_service_connect| fort details.
+// See |fdio_open_at| fort details.
 zx_status_t fdio_open_fd_at(int dir_fd, const char* path, uint32_t flags, int* out_fd)
     ZX_AVAILABLE_SINCE(1);
 
diff --git a/sdk/lib/fdio/include/lib/fdio/namespace.h b/sdk/lib/fdio/include/lib/fdio/namespace.h
index 090dfaf..7af2079 100644
--- a/sdk/lib/fdio/include/lib/fdio/namespace.h
+++ b/sdk/lib/fdio/include/lib/fdio/namespace.h
@@ -108,7 +108,58 @@
 // or passed to the remote service on success.
 // The path must be an absolute path starting with /.
 zx_status_t fdio_ns_connect(fdio_ns_t* ns, const char* path, uint32_t flags, zx_handle_t request)
-    ZX_AVAILABLE_SINCE(1);
+    ZX_DEPRECATED_SINCE(1, 8,
+                        "Incorrectly named due to accepting flags. Use fdio_ns_open or "
+                        "fdio_ns_service_connect instead.");
+
+// Opens an object at |path| relative to the root of |ns| with |flags|
+// asynchronously.
+//
+// |path| is looked up in |ns|. If found, the object at |path| is opened,
+// passing |request| to the remote party.
+//
+// Upon success, |request| is handed off to the remote party. The operation
+// completes asynchronously, which means a ZX_OK result does not ensure that the
+// requested service actually exists.
+//
+// |path| must be absolute.
+//
+// |flags| is a |fuchsia.io/OpenFlags|.
+//
+// |request| must be a channel.
+//
+// Always consumes |request|.
+//
+// # Errors
+//
+// ZX_ERR_INVALID_ARGS: |path| is invalid.
+//
+// ZX_ERR_NOT_FOUND: A prefix of |path| cannot be found in |ns|.
+zx_status_t fdio_ns_open(fdio_ns_t* ns, const char* path, uint32_t flags, zx_handle_t request)
+    ZX_AVAILABLE_SINCE(8);
+
+// Connects to a service at |path| relative to the root of |ns| asynchronously.
+//
+// |path| is looked up in |ns|. If found, the object at |path| is opened,
+// passing |request| to the remote party.
+//
+// Upon success, |request| is handed off to the remote party. The operation
+// completes asynchronously, which means a ZX_OK result does not ensure that the
+// requested service actually exists.
+//
+// |path| must be absolute.
+//
+// |request| must be a channel.
+//
+// Always consumes |request|.
+//
+// # Errors
+//
+// ZX_ERR_INVALID_ARGS: |path| is invalid.
+//
+// ZX_ERR_NOT_FOUND: A prefix of |path| cannot be found in |ns|.
+zx_status_t fdio_ns_service_connect(fdio_ns_t* ns, const char* path, zx_handle_t request)
+    ZX_AVAILABLE_SINCE(8);
 
 // Frees a flat namespace.
 // Closes all handles contained within |ns|.
diff --git a/sdk/lib/fdio/namespace/namespace.cc b/sdk/lib/fdio/namespace/namespace.cc
index 92db65f..072c4cca 100644
--- a/sdk/lib/fdio/namespace/namespace.cc
+++ b/sdk/lib/fdio/namespace/namespace.cc
@@ -13,9 +13,12 @@
 #include <fbl/ref_ptr.h>
 
 #include "../fdio_unistd.h"
+#include "fidl/fuchsia.io/cpp/wire_types.h"
 #include "local-connection.h"
 #include "local-filesystem.h"
 
+namespace fio = fuchsia_io;
+
 zx::status<fdio_ptr> fdio_ns_open_root(fdio_ns_t* ns) { return ns->OpenRoot(); }
 
 zx_status_t fdio_ns_set_root(fdio_ns_t* ns, fdio_t* io) { return ns->SetRoot(io); }
@@ -24,6 +27,14 @@
 
 __EXPORT
 zx_status_t fdio_ns_connect(fdio_ns_t* ns, const char* path, uint32_t flags, zx_handle_t request) {
+  if (static_cast<fio::wire::OpenFlags>(flags) & fio::wire::OpenFlags::kDescribe) {
+    return ZX_ERR_INVALID_ARGS;
+  }
+  return fdio_ns_open(ns, path, flags, request);
+}
+
+__EXPORT
+zx_status_t fdio_ns_open(fdio_ns_t* ns, const char* path, uint32_t flags, zx_handle_t request) {
   if (path == nullptr) {
     return ZX_ERR_INVALID_ARGS;
   }
@@ -32,8 +43,15 @@
   if (!fdio_internal::CleanPath(path, &clean, &is_dir)) {
     return ZX_ERR_BAD_PATH;
   }
-  auto remote = fidl::ServerEnd<fuchsia_io::Node>(zx::channel(request));
-  return ns->Connect(clean, static_cast<fuchsia_io::wire::OpenFlags>(flags), std::move(remote));
+  auto remote = fidl::ServerEnd<fio::Node>(zx::channel(request));
+  return ns->Connect(clean, static_cast<fio::wire::OpenFlags>(flags), std::move(remote));
+}
+
+__EXPORT
+zx_status_t fdio_ns_service_connect(fdio_ns_t* ns, const char* path, zx_handle_t request) {
+  // TODO(https://fxbug.dev/101092): Shrink this to 0.
+  constexpr uint32_t flags = static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable);
+  return fdio_ns_open(ns, path, flags, request);
 }
 
 __EXPORT
@@ -64,7 +82,7 @@
   if (!fdio_internal::CleanPath(path, &clean, &is_dir)) {
     return ZX_ERR_BAD_PATH;
   }
-  auto remote = fidl::ClientEnd<fuchsia_io::Directory>(zx::channel(remote_raw));
+  auto remote = fidl::ClientEnd<fio::Directory>(zx::channel(remote_raw));
   return ns->Bind(clean, std::move(remote));
 }
 
diff --git a/sdk/lib/fdio/tests/fdio_namespace.cc b/sdk/lib/fdio/tests/fdio_namespace.cc
index 24db3d5..6dc14c0 100644
--- a/sdk/lib/fdio/tests/fdio_namespace.cc
+++ b/sdk/lib/fdio/tests/fdio_namespace.cc
@@ -34,7 +34,7 @@
 
   zx::channel service0, service1;
   ASSERT_OK(zx::channel::create(0, &service0, &service1));
-  EXPECT_STATUS(fdio_ns_connect(ns, nullptr, 0, service0.release()), ZX_ERR_INVALID_ARGS);
+  EXPECT_STATUS(fdio_ns_open(ns, nullptr, 0, service0.release()), ZX_ERR_INVALID_ARGS);
 
   ASSERT_OK(fdio_ns_destroy(ns));
 }
@@ -115,7 +115,7 @@
 
   zx::channel service0, service1;
   ASSERT_OK(zx::channel::create(0, &service0, &service1));
-  ASSERT_OK(fdio_ns_connect(ns, "//foo/fake_subdir/.././Service", 1u, service0.release()));
+  ASSERT_OK(fdio_ns_open(ns, "//foo/fake_subdir/.././Service", 1u, service0.release()));
 
   // Expect an incoming connect on ch1
   ASSERT_OK(fdio_ns_destroy(ns));
@@ -135,7 +135,7 @@
   // for a null terminator. This path is thus too long by one character.
   EXPECT_EQ(long_path.length(), PATH_MAX);
 
-  EXPECT_STATUS(fdio_ns_connect(ns, long_path.c_str(), 0u, ch0.release()), ZX_ERR_BAD_PATH);
+  EXPECT_STATUS(fdio_ns_open(ns, long_path.c_str(), 0u, ch0.release()), ZX_ERR_BAD_PATH);
 
   ASSERT_OK(fdio_ns_destroy(ns));
 }
@@ -152,8 +152,7 @@
   // component is thus too long by one character.
   long_path_component.append(NAME_MAX + 1, 'a');
 
-  EXPECT_STATUS(fdio_ns_connect(ns, long_path_component.c_str(), 0u, ch0.release()),
-                ZX_ERR_BAD_PATH);
+  EXPECT_STATUS(fdio_ns_open(ns, long_path_component.c_str(), 0u, ch0.release()), ZX_ERR_BAD_PATH);
 
   ASSERT_OK(fdio_ns_destroy(ns));
 }
diff --git a/sdk/lib/sys/component/cpp/testing/realm_builder_types.cc b/sdk/lib/sys/component/cpp/testing/realm_builder_types.cc
index c506f7f..d656efb 100644
--- a/sdk/lib/sys/component/cpp/testing/realm_builder_types.cc
+++ b/sdk/lib/sys/component/cpp/testing/realm_builder_types.cc
@@ -79,13 +79,14 @@
   zx::channel remote;
   ZX_COMPONENT_ASSERT_STATUS_OK("zx::channel/create", zx::channel::create(0, &local, &remote));
 
-  auto status = fdio_ns_connect(namespace_, kSvcDirectoryPath,
-                                static_cast<uint32_t>(fuchsia::io::OpenFlags::RIGHT_READABLE |
-                                                      fuchsia::io::OpenFlags::RIGHT_WRITABLE),
-                                remote.release());
+  // TODO(https://fxbug.dev/101092): Replace this with fdio_ns_service_connect when
+  // ServiceDirectory::Connect (via fdio_service_connect_at) no longer requests R/W.
+  constexpr uint32_t kServiceFlags = static_cast<uint32_t>(fuchsia::io::OpenFlags::RIGHT_READABLE |
+                                                           fuchsia::io::OpenFlags::RIGHT_WRITABLE);
+  auto status = fdio_ns_open(namespace_, kSvcDirectoryPath, kServiceFlags, remote.release());
   ZX_ASSERT_MSG(status == ZX_OK,
-                "fdio_ns_connect on LocalComponent's /svc directory failed: %s\nThis most often "
-                "occurs when a component has no FIDL protocols routed to it.",
+                "fdio_ns_service_connect on LocalComponent's /svc directory failed: %s\nThis most"
+                "often occurs when a component has no FIDL protocols routed to it.",
                 zx_status_get_string(status));
 
   return sys::ServiceDirectory(std::move(local));
diff --git a/sdk/lib/sys/service/cpp/service.cc b/sdk/lib/sys/service/cpp/service.cc
index 9edd744..8d37b32 100644
--- a/sdk/lib/sys/service/cpp/service.cc
+++ b/sdk/lib/sys/service/cpp/service.cc
@@ -55,9 +55,8 @@
   path += service_path + '/' + instance;
 
   fidl::InterfaceHandle<fuchsia::io::Directory> dir;
-  zx_status_t status = fdio_ns_connect(
-      ns, path.data(), static_cast<uint32_t>(fuchsia::io::OpenFlags::RIGHT_READABLE),
-      dir.NewRequest().TakeChannel().release());
+  zx_status_t status =
+      fdio_ns_service_connect(ns, path.data(), dir.NewRequest().TakeChannel().release());
   if (status != ZX_OK) {
     return nullptr;
   }
diff --git a/sdk/lib/sys/service/cpp/service_aggregate.cc b/sdk/lib/sys/service/cpp/service_aggregate.cc
index aaf7912..b8a3660 100644
--- a/sdk/lib/sys/service/cpp/service_aggregate.cc
+++ b/sdk/lib/sys/service/cpp/service_aggregate.cc
@@ -61,9 +61,8 @@
   path += service_path;
 
   fidl::InterfaceHandle<fuchsia::io::Directory> dir;
-  zx_status_t status = fdio_ns_connect(
-      ns, path.data(), static_cast<uint32_t>(fuchsia::io::OpenFlags::RIGHT_READABLE),
-      dir.NewRequest().TakeChannel().release());
+  zx_status_t status =
+      fdio_ns_service_connect(ns, path.data(), dir.NewRequest().TakeChannel().release());
   if (status != ZX_OK) {
     return nullptr;
   }
diff --git a/sdk/lib/sys/service/cpp/service_aggregate_test.cc b/sdk/lib/sys/service/cpp/service_aggregate_test.cc
index 882d7d4..227aaf2 100644
--- a/sdk/lib/sys/service/cpp/service_aggregate_test.cc
+++ b/sdk/lib/sys/service/cpp/service_aggregate_test.cc
@@ -16,8 +16,7 @@
 TEST_F(ServiceAggregateTest, OpenServiceAggregateAt) {
   fidl::InterfaceHandle<fuchsia::io::Directory> directory;
   zx_status_t status =
-      fdio_ns_connect(ns(), "/svc", static_cast<uint32_t>(fuchsia::io::OpenFlags::RIGHT_READABLE),
-                      directory.NewRequest().TakeChannel().release());
+      fdio_ns_service_connect(ns(), "/svc", directory.NewRequest().TakeChannel().release());
   ASSERT_EQ(ZX_OK, status);
 
   auto service_aggregate = OpenServiceAggregateAt<fuchsia::examples::EchoService>(directory);
diff --git a/sdk/lib/sys/service/cpp/service_test.cc b/sdk/lib/sys/service/cpp/service_test.cc
index 7dae8b6..9773eb2 100644
--- a/sdk/lib/sys/service/cpp/service_test.cc
+++ b/sdk/lib/sys/service/cpp/service_test.cc
@@ -14,8 +14,7 @@
 TEST_F(ServiceTest, OpenServiceAt) {
   fidl::InterfaceHandle<fuchsia::io::Directory> directory;
   zx_status_t status =
-      fdio_ns_connect(ns(), "/svc", static_cast<uint32_t>(fuchsia::io::OpenFlags::RIGHT_READABLE),
-                      directory.NewRequest().TakeChannel().release());
+      fdio_ns_service_connect(ns(), "/svc", directory.NewRequest().TakeChannel().release());
   ASSERT_EQ(ZX_OK, status);
 
   auto default_service = OpenServiceAt<fuchsia::examples::EchoService>(directory);
diff --git a/src/devices/tests/devfs/fidl-tests.cc b/src/devices/tests/devfs/fidl-tests.cc
index 0d1f91b..5fd2ef1 100644
--- a/src/devices/tests/devfs/fidl-tests.cc
+++ b/src/devices/tests/devfs/fidl-tests.cc
@@ -71,9 +71,7 @@
     ASSERT_OK(endpoints.status_value());
     fdio_ns_t* ns;
     ASSERT_OK(fdio_ns_get_installed(&ns));
-    ASSERT_OK(fdio_ns_connect(ns, "/dev",
-                              static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable),
-                              endpoints->server.channel().release()));
+    ASSERT_OK(fdio_ns_service_connect(ns, "/dev", endpoints->server.channel().release()));
     ASSERT_NO_FAILURES(
         FidlOpenValidator(endpoints->client, "zero", zx::ok(fio::wire::NodeInfo::Tag::kDevice)));
     ASSERT_NO_FAILURES(FidlOpenValidator(endpoints->client, "class/platform-bus/000",
@@ -90,9 +88,7 @@
     ASSERT_OK(endpoints.status_value());
     fdio_ns_t* ns;
     ASSERT_OK(fdio_ns_get_installed(&ns));
-    ASSERT_OK(fdio_ns_connect(ns, "/boot",
-                              static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable),
-                              endpoints->server.channel().release()));
+    ASSERT_OK(fdio_ns_service_connect(ns, "/boot", endpoints->server.channel().release()));
     ASSERT_NO_FAILURES(
         FidlOpenValidator(endpoints->client, "lib", zx::ok(fio::wire::NodeInfo::Tag::kDirectory)));
     ASSERT_NO_FAILURES(FidlOpenValidator(endpoints->client, "this-path-better-not-actually-exist",
diff --git a/src/lib/fdio/rust/BUILD.gn b/src/lib/fdio/rust/BUILD.gn
index 12cca98..c4c6613 100644
--- a/src/lib/fdio/rust/BUILD.gn
+++ b/src/lib/fdio/rust/BUILD.gn
@@ -25,6 +25,8 @@
     "//src/lib/fuchsia-async",
     "//src/lib/fuchsia-runtime",
     "//third_party/rust_crates:assert_matches",
+    "//third_party/rust_crates:libc",
+    "//third_party/rust_crates:rand",
     "//third_party/rust_crates:tempfile",
   ]
 
diff --git a/src/lib/fdio/rust/src/fdio_sys.rs b/src/lib/fdio/rust/src/fdio_sys.rs
index eda17ec..504084f 100644
--- a/src/lib/fdio/rust/src/fdio_sys.rs
+++ b/src/lib/fdio/rust/src/fdio_sys.rs
@@ -330,6 +330,21 @@
     ) -> zx_status_t;
 }
 extern "C" {
+    pub fn fdio_ns_open(
+        ns: *mut fdio_ns_t,
+        path: *const ::std::os::raw::c_char,
+        flags: u32,
+        request: zx_handle_t,
+    ) -> zx_status_t;
+}
+extern "C" {
+    pub fn fdio_ns_service_connect(
+        ns: *mut fdio_ns_t,
+        path: *const ::std::os::raw::c_char,
+        request: zx_handle_t,
+    ) -> zx_status_t;
+}
+extern "C" {
     pub fn fdio_ns_free_flat_ns(ns: *mut fdio_flat_namespace_t);
 }
 extern "C" {
diff --git a/src/lib/fdio/rust/src/lib.rs b/src/lib/fdio/rust/src/lib.rs
index 7efda51..5aecada 100644
--- a/src/lib/fdio/rust/src/lib.rs
+++ b/src/lib/fdio/rust/src/lib.rs
@@ -651,12 +651,12 @@
         Ok(Namespace { ns })
     }
 
-    /// Create a channel that is connected to a service bound in this namespace at path. The path
-    /// must be an absolute path, like "/x/y/z", containing no "." nor ".." entries. It is relative
-    /// to the root of the namespace.
+    /// Open an object at |path| relative to the root of this namespace with |flags|.
     ///
-    /// This corresponds with fdio_ns_connect in C.
-    pub fn connect(
+    /// |path| must be absolute.
+    ///
+    /// This corresponds with fdio_ns_open in C.
+    pub fn open(
         &self,
         path: &str,
         flags: fio::OpenFlags,
@@ -669,7 +669,7 @@
 
         // The channel is always consumed.
         let channel = channel.into_raw();
-        let status = unsafe { fdio_sys::fdio_ns_connect(ns, path, flags, channel) };
+        let status = unsafe { fdio_sys::fdio_ns_open(ns, path, flags, channel) };
         zx::Status::ok(status)
     }
 
@@ -749,7 +749,7 @@
     }
 
     #[test]
-    fn namespace_bind_connect_unbind() {
+    fn namespace_bind_open_unbind() {
         let namespace = Namespace::installed().unwrap();
         // client => ns_server => ns_client => server
         //        ^            ^            ^-- zx channel connection
@@ -760,7 +760,7 @@
         let path = "/test_path1";
 
         assert_eq!(namespace.bind(path, ns_client), Ok(()));
-        assert_eq!(namespace.connect(path, fio::OpenFlags::empty(), ns_server), Ok(()));
+        assert_eq!(namespace.open(path, fio::OpenFlags::empty(), ns_server), Ok(()));
         assert_eq!(namespace.unbind(path), Ok(()));
     }
 
@@ -777,13 +777,13 @@
     }
 
     #[test]
-    fn namespace_connect_error() {
+    fn namespace_open_error() {
         let namespace = Namespace::installed().unwrap();
         let (_client, ns_server) = zx::Channel::create().unwrap();
         let path = "/test_path3";
 
         assert_eq!(
-            namespace.connect(path, fio::OpenFlags::empty(), ns_server),
+            namespace.open(path, fio::OpenFlags::empty(), ns_server),
             Err(zx::Status::NOT_FOUND)
         );
     }
@@ -873,27 +873,30 @@
     // exercise one success and one failure case for each function.
     #[test]
     fn fdio_open_and_open_at() {
+        use rand::distributions::DistString as _;
+
         // fdio_open requires paths to be absolute
-        let (_, pkg_server) = zx::Channel::create().unwrap();
-        assert_eq!(
-            open("pkg", fio::OpenFlags::RIGHT_READABLE, pkg_server),
-            Err(zx::Status::NOT_FOUND)
-        );
+        {
+            let (_, pkg_server) = zx::Channel::create().unwrap();
+            assert_eq!(
+                open("pkg", fio::OpenFlags::RIGHT_READABLE, pkg_server),
+                Err(zx::Status::NOT_FOUND)
+            );
+        }
 
         let (pkg_client, pkg_server) = zx::Channel::create().unwrap();
         assert_eq!(open("/pkg", fio::OpenFlags::RIGHT_READABLE, pkg_server), Ok(()));
 
-        // fdio_open/fdio_open_at do not support OPEN_FLAG_DESCRIBE
-        let (_, bin_server) = zx::Channel::create().unwrap();
-        assert_eq!(
-            open_at(
-                &pkg_client,
-                "bin",
-                fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::DESCRIBE,
-                bin_server
-            ),
-            Err(zx::Status::INVALID_ARGS)
-        );
+        // fdio_open/fdio_open_at disallow paths that are too long
+        {
+            let path = rand::distributions::Alphanumeric
+                .sample_string(&mut rand::thread_rng(), libc::PATH_MAX.try_into().unwrap());
+            let (_, server) = zx::Channel::create().unwrap();
+            assert_eq!(
+                open_at(&pkg_client, &path, fio::OpenFlags::empty(), server),
+                Err(zx::Status::INVALID_ARGS)
+            );
+        }
 
         let (_, bin_server) = zx::Channel::create().unwrap();
         assert_eq!(open_at(&pkg_client, "bin", fio::OpenFlags::RIGHT_READABLE, bin_server), Ok(()));
diff --git a/src/lib/fuchsia-fs/src/node.rs b/src/lib/fuchsia-fs/src/node.rs
index 0ce8a88..b591941 100644
--- a/src/lib/fuchsia-fs/src/node.rs
+++ b/src/lib/fuchsia-fs/src/node.rs
@@ -183,8 +183,7 @@
     chan: zx::Channel,
 ) -> Result<(), zx_status::Status> {
     let namespace = fdio::Namespace::installed()?;
-    namespace.connect(path, flags, chan)?;
-    Ok(())
+    namespace.open(path, flags, chan)
 }
 
 /// Opens the given `path` from the current namespace as a [`NodeProxy`]. The target is not
diff --git a/src/lib/storage/fs_management/rust/src/lib.rs b/src/lib/storage/fs_management/rust/src/lib.rs
index 35d4c31..1201c5b 100644
--- a/src/lib/storage/fs_management/rust/src/lib.rs
+++ b/src/lib/storage/fs_management/rust/src/lib.rs
@@ -49,7 +49,7 @@
 use {
     anyhow::{bail, format_err, Context as _, Error},
     cstr::cstr,
-    fdio::{service_connect_at, spawn_etc, Namespace, SpawnAction, SpawnOptions},
+    fdio::{service_connect, service_connect_at, spawn_etc, Namespace, SpawnAction, SpawnOptions},
     fidl::endpoints::DiscoverableProtocolMarker,
     fidl_fuchsia_fs::AdminSynchronousProxy,
     fidl_fuchsia_io as fio,
@@ -163,9 +163,7 @@
     fn query_filesystem(&self) -> Result<Box<fio::FilesystemInfo>, Error> {
         let (client_chan, server_chan) = zx::Channel::create()?;
 
-        let namespace = Namespace::installed().context("failed to get installed namespace")?;
-        namespace
-            .connect(&self.mount_point, fio::OpenFlags::RIGHT_READABLE, server_chan)
+        service_connect(&self.mount_point, server_chan)
             .context("failed to connect to filesystem")?;
 
         let proxy = fio::DirectorySynchronousProxy::new(client_chan);
@@ -286,8 +284,7 @@
     /// modified at this point.
     pub fn from_path(device_path: &str, config: FSC) -> Result<Self, Error> {
         let (client_end, server_end) = zx::Channel::create()?;
-        fdio::service_connect(device_path, server_end)
-            .context("could not connect to block device")?;
+        service_connect(device_path, server_end).context("could not connect to block device")?;
         Self::from_channel(client_end, config)
     }