[libvfs] Add a function to remove node from directory.

Adding a function which also take Node* so that clients can have more
confidence in what they are removing.

More context: https://fuchsia-review.googlesource.com/c/fuchsia/+/249338

DX-387 #comment

TEST=CQ

Change-Id: Ia73e9c414ff393adeed2110a3c428583f9685b2f
diff --git a/sdk/lib/vfs/cpp/pseudo_dir.cc b/sdk/lib/vfs/cpp/pseudo_dir.cc
index d4b6684..6d616be 100644
--- a/sdk/lib/vfs/cpp/pseudo_dir.cc
+++ b/sdk/lib/vfs/cpp/pseudo_dir.cc
@@ -62,6 +62,18 @@
   return ZX_OK;
 }
 
+zx_status_t PseudoDir::RemoveEntry(const std::string& name, Node* node) {
+  std::lock_guard<std::mutex> guard(mutex_);
+  auto entry = entries_by_name_.find(name);
+  if (entry == entries_by_name_.end() || entry->second->node() != node) {
+    return ZX_ERR_NOT_FOUND;
+  }
+  entries_by_id_.erase(entry->second->id());
+  entries_by_name_.erase(name);
+
+  return ZX_OK;
+}
+
 zx_status_t PseudoDir::Lookup(const std::string& name, Node** out_node) const {
   std::lock_guard<std::mutex> guard(mutex_);
 
diff --git a/sdk/lib/vfs/cpp/pseudo_dir.h b/sdk/lib/vfs/cpp/pseudo_dir.h
index b562b480..188410a 100644
--- a/sdk/lib/vfs/cpp/pseudo_dir.h
+++ b/sdk/lib/vfs/cpp/pseudo_dir.h
@@ -47,6 +47,13 @@
   // Returns |ZX_ERR_NOT_FOUND| if there is no node with the given name.
   zx_status_t RemoveEntry(const std::string& name);
 
+  // Removes a directory entry with the given |name| and |node|.
+  //
+  // Returns |ZX_OK| on success.
+  // Returns |ZX_ERR_NOT_FOUND| if there is no node with the given |name| and
+  // matching |node| pointer.
+  zx_status_t RemoveEntry(const std::string& name, Node* node);
+
   // Removes all directory entries.
   void RemoveAllEntries();
 
diff --git a/sdk/lib/vfs/cpp/pseudo_dir_unittest.cc b/sdk/lib/vfs/cpp/pseudo_dir_unittest.cc
index a022b4e..857dcae 100644
--- a/sdk/lib/vfs/cpp/pseudo_dir_unittest.cc
+++ b/sdk/lib/vfs/cpp/pseudo_dir_unittest.cc
@@ -110,6 +110,23 @@
   ASSERT_TRUE(dir_.IsEmpty());
 }
 
+TEST_F(PseudoDirUnit, RemoveEntryWithNode) {
+  Init(5);
+  for (int i = 0; i < 5; i++) {
+    ASSERT_EQ(2, nodes_[i].use_count());
+    ASSERT_EQ(ZX_OK, dir_.RemoveEntry(node_names_[i], nodes_[i].get()))
+        << "for " << node_names_[i];
+
+    // cannot access
+    vfs::Node* n;
+    ASSERT_EQ(ZX_ERR_NOT_FOUND, dir_.Lookup(node_names_[i], &n))
+        << "for " << node_names_[i];
+    // check that use count went down by 1
+    ASSERT_EQ(1, nodes_[i].use_count());
+  }
+  ASSERT_TRUE(dir_.IsEmpty());
+}
+
 TEST_F(PseudoDirUnit, RemoveUniqueNode) {
   Init(0);
 
@@ -536,8 +553,9 @@
 TEST_F(PseudoDirConnection, OpenSelf) {
   std::string paths[] = {
       ".",      "./",
-      ".//",    "././",  "././/.",
-      "././//", "././/", "././././/././././////./././//././/./././/././."};
+      ".//",    "././",
+      "././/.", "././//",
+      "././/",  "././././/././././////./././//././/./././/././."};
   auto subdir = std::make_shared<vfs::PseudoDir>();
   dir_.AddSharedEntry("subdir", subdir);
   auto ptr = dir_.Serve();