Version 2.18.0-116.0.dev

Merge commit 'e8290f7f5a0a235612b8d3e732092bbee0ccd2b7' into 'dev'
diff --git a/runtime/bin/file.h b/runtime/bin/file.h
index f2d45e9..802cf05 100644
--- a/runtime/bin/file.h
+++ b/runtime/bin/file.h
@@ -70,7 +70,14 @@
     kDartWriteOnlyAppend = 4
   };
 
-  enum Type { kIsFile = 0, kIsDirectory = 1, kIsLink = 2, kDoesNotExist = 3 };
+  enum Type {
+    kIsFile = 0,
+    kIsDirectory = 1,
+    kIsLink = 2,
+    kIsSock = 3,  // Unix Domain Socket.
+    kIsPipe = 4,  // FIFO/Pipe.
+    kDoesNotExist = 5
+  };
 
   enum Identical { kIdentical = 0, kDifferent = 1, kError = 2 };
 
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index d766192..a93c1fb 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -356,18 +356,17 @@
   if (S_ISLNK(entry_info.st_mode)) {
     return File::kIsLink;
   }
+  if (S_ISSOCK(entry_info.st_mode)) {
+    return File::kIsSock;
+  }
+  if (S_ISFIFO(entry_info.st_mode)) {
+    return File::kIsPipe;
+  }
   return File::kDoesNotExist;
 }
 
-static bool CheckTypeAndSetErrno(Namespace* namespc,
-                                 const char* name,
-                                 File::Type expected,
-                                 bool follow_links) {
-  File::Type actual = File::GetType(namespc, name, follow_links);
-  if (actual == expected) {
-    return true;
-  }
-  switch (actual) {
+static void SetErrno(File::Type type) {
+  switch (type) {
     case File::kIsDirectory:
       errno = EISDIR;
       break;
@@ -378,13 +377,28 @@
       errno = EINVAL;
       break;
   }
+}
+
+static bool CheckTypeAndSetErrno(Namespace* namespc,
+                                 const char* name,
+                                 File::Type expected,
+                                 bool follow_links) {
+  File::Type actual = File::GetType(namespc, name, follow_links);
+  if (actual == expected) {
+    return true;
+  }
+  SetErrno(actual);
   return false;
 }
 
 bool File::Delete(Namespace* namespc, const char* name) {
   NamespaceScope ns(namespc, name);
-  return CheckTypeAndSetErrno(namespc, name, kIsFile, true) &&
-         (NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), 0)) == 0);
+  File::Type type = File::GetType(namespc, name, true);
+  if (type == kIsFile || type == kIsSock || type == kIsPipe) {
+    return (NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), 0)) == 0);
+  }
+  SetErrno(type);
+  return false;
 }
 
 bool File::DeleteLink(Namespace* namespc, const char* name) {
@@ -396,11 +410,15 @@
 bool File::Rename(Namespace* namespc,
                   const char* old_path,
                   const char* new_path) {
-  NamespaceScope oldns(namespc, old_path);
-  NamespaceScope newns(namespc, new_path);
-  return CheckTypeAndSetErrno(namespc, old_path, kIsFile, true) &&
-         (NO_RETRY_EXPECTED(renameat(oldns.fd(), oldns.path(), newns.fd(),
-                                     newns.path())) == 0);
+  File::Type type = File::GetType(namespc, old_path, true);
+  if (type == kIsFile || type == kIsSock || type == kIsPipe) {
+    NamespaceScope oldns(namespc, old_path);
+    NamespaceScope newns(namespc, new_path);
+    return (NO_RETRY_EXPECTED(renameat(oldns.fd(), oldns.path(), newns.fd(),
+                                       newns.path())) == 0);
+  }
+  SetErrno(type);
+  return false;
 }
 
 bool File::RenameLink(Namespace* namespc,
@@ -416,7 +434,9 @@
 bool File::Copy(Namespace* namespc,
                 const char* old_path,
                 const char* new_path) {
-  if (!CheckTypeAndSetErrno(namespc, old_path, kIsFile, true)) {
+  File::Type type = File::GetType(namespc, old_path, true);
+  if (type != kIsFile && type != kIsSock && type != kIsPipe) {
+    SetErrno(type);
     return false;
   }
   NamespaceScope oldns(namespc, old_path);
@@ -508,6 +528,10 @@
       data[kType] = kIsDirectory;
     } else if (S_ISLNK(st.st_mode)) {
       data[kType] = kIsLink;
+    } else if (S_ISSOCK(st.st_mode)) {
+      data[kType] = kIsSock;
+    } else if (S_ISFIFO(st.st_mode)) {
+      data[kType] = kIsPipe;
     } else {
       data[kType] = kDoesNotExist;
     }
diff --git a/runtime/bin/file_fuchsia.cc b/runtime/bin/file_fuchsia.cc
index aa7f882..57765f0 100644
--- a/runtime/bin/file_fuchsia.cc
+++ b/runtime/bin/file_fuchsia.cc
@@ -354,18 +354,17 @@
   if (S_ISLNK(entry_info.st_mode)) {
     return File::kIsLink;
   }
+  if (S_ISSOCK(entry_info.st_mode)) {
+    return File::kIsSock;
+  }
+  if (S_ISFIFO(entry_info.st_mode)) {
+    return File::kIsPipe;
+  }
   return File::kDoesNotExist;
 }
 
-static bool CheckTypeAndSetErrno(Namespace* namespc,
-                                 const char* name,
-                                 File::Type expected,
-                                 bool follow_links) {
-  File::Type actual = File::GetType(namespc, name, follow_links);
-  if (actual == expected) {
-    return true;
-  }
-  switch (actual) {
+static void SetErrno(File::Type type) {
+  switch (type) {
     case File::kIsDirectory:
       errno = EISDIR;
       break;
@@ -376,13 +375,28 @@
       errno = EINVAL;
       break;
   }
+}
+
+static bool CheckTypeAndSetErrno(Namespace* namespc,
+                                 const char* name,
+                                 File::Type expected,
+                                 bool follow_links) {
+  File::Type actual = File::GetType(namespc, name, follow_links);
+  if (actual == expected) {
+    return true;
+  }
+  SetErrno(actual);
   return false;
 }
 
 bool File::Delete(Namespace* namespc, const char* name) {
-  NamespaceScope ns(namespc, name);
-  return CheckTypeAndSetErrno(namespc, name, kIsFile, true) &&
-         (NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), 0)) == 0);
+  File::Type type = File::GetType(namespc, name, true);
+  if (type == kIsFile || type == kIsSock || type == kIsPipe) {
+    NamespaceScope ns(namespc, name);
+    return (NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), 0)) == 0);
+  }
+  SetErrno(type);
+  return false;
 }
 
 bool File::DeleteLink(Namespace* namespc, const char* name) {
@@ -394,11 +408,15 @@
 bool File::Rename(Namespace* namespc,
                   const char* old_path,
                   const char* new_path) {
-  NamespaceScope oldns(namespc, old_path);
-  NamespaceScope newns(namespc, new_path);
-  return CheckTypeAndSetErrno(namespc, old_path, kIsFile, true) &&
-         (NO_RETRY_EXPECTED(renameat(oldns.fd(), oldns.path(), newns.fd(),
-                                     newns.path())) == 0);
+  File::Type type = File::GetType(namespc, old_path, true);
+  if (type == kIsFile || type == kIsSock || type == kIsPipe) {
+    NamespaceScope oldns(namespc, old_path);
+    NamespaceScope newns(namespc, new_path);
+    return (NO_RETRY_EXPECTED(renameat(oldns.fd(), oldns.path(), newns.fd(),
+                                       newns.path())) == 0);
+  }
+  SetErrno(type);
+  return false;
 }
 
 bool File::RenameLink(Namespace* namespc,
@@ -414,7 +432,9 @@
 bool File::Copy(Namespace* namespc,
                 const char* old_path,
                 const char* new_path) {
-  if (!CheckTypeAndSetErrno(namespc, old_path, kIsFile, true)) {
+  File::Type type = File::GetType(namespc, old_path, true);
+  if (type != kIsFile && type != kIsSock && type != kIsPipe) {
+    SetErrno(type);
     return false;
   }
   NamespaceScope oldns(namespc, old_path);
@@ -503,6 +523,10 @@
       data[kType] = kIsDirectory;
     } else if (S_ISLNK(st.st_mode)) {
       data[kType] = kIsLink;
+    } else if (S_ISSOCK(st.st_mode)) {
+      data[kType] = kIsSock;
+    } else if (S_ISFIFO(st.st_mode)) {
+      data[kType] = kIsPipe;
     } else {
       data[kType] = kDoesNotExist;
     }
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index 625f054..994bcbd 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -350,18 +350,17 @@
   if (S_ISLNK(entry_info.st_mode)) {
     return File::kIsLink;
   }
+  if (S_ISSOCK(entry_info.st_mode)) {
+    return File::kIsSock;
+  }
+  if (S_ISFIFO(entry_info.st_mode)) {
+    return File::kIsPipe;
+  }
   return File::kDoesNotExist;
 }
 
-static bool CheckTypeAndSetErrno(Namespace* namespc,
-                                 const char* name,
-                                 File::Type expected,
-                                 bool follow_links) {
-  File::Type actual = File::GetType(namespc, name, follow_links);
-  if (actual == expected) {
-    return true;
-  }
-  switch (actual) {
+static void SetErrno(File::Type type) {
+  switch (type) {
     case File::kIsDirectory:
       errno = EISDIR;
       break;
@@ -372,13 +371,28 @@
       errno = EINVAL;
       break;
   }
+}
+
+static bool CheckTypeAndSetErrno(Namespace* namespc,
+                                 const char* name,
+                                 File::Type expected,
+                                 bool follow_links) {
+  File::Type actual = File::GetType(namespc, name, follow_links);
+  if (actual == expected) {
+    return true;
+  }
+  SetErrno(actual);
   return false;
 }
 
 bool File::Delete(Namespace* namespc, const char* name) {
-  NamespaceScope ns(namespc, name);
-  return CheckTypeAndSetErrno(namespc, name, kIsFile, true) &&
-         (NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), 0)) == 0);
+  File::Type type = File::GetType(namespc, name, true);
+  if (type == kIsFile || type == kIsSock || type == kIsPipe) {
+    NamespaceScope ns(namespc, name);
+    return (NO_RETRY_EXPECTED(unlinkat(ns.fd(), ns.path(), 0)) == 0);
+  }
+  SetErrno(type);
+  return false;
 }
 
 bool File::DeleteLink(Namespace* namespc, const char* name) {
@@ -390,11 +404,15 @@
 bool File::Rename(Namespace* namespc,
                   const char* old_path,
                   const char* new_path) {
-  NamespaceScope oldns(namespc, old_path);
-  NamespaceScope newns(namespc, new_path);
-  return CheckTypeAndSetErrno(namespc, old_path, kIsFile, true) &&
-         (NO_RETRY_EXPECTED(renameat(oldns.fd(), oldns.path(), newns.fd(),
-                                     newns.path())) == 0);
+  File::Type type = File::GetType(namespc, old_path, true);
+  if (type == kIsFile || type == kIsSock || type == kIsPipe) {
+    NamespaceScope oldns(namespc, old_path);
+    NamespaceScope newns(namespc, new_path);
+    return (NO_RETRY_EXPECTED(renameat(oldns.fd(), oldns.path(), newns.fd(),
+                                       newns.path())) == 0);
+  }
+  SetErrno(type);
+  return false;
 }
 
 bool File::RenameLink(Namespace* namespc,
@@ -410,7 +428,9 @@
 bool File::Copy(Namespace* namespc,
                 const char* old_path,
                 const char* new_path) {
-  if (!CheckTypeAndSetErrno(namespc, old_path, kIsFile, true)) {
+  File::Type type = File::GetType(namespc, old_path, true);
+  if (type != kIsFile && type != kIsSock && type != kIsPipe) {
+    SetErrno(type);
     return false;
   }
   NamespaceScope oldns(namespc, old_path);
@@ -509,6 +529,10 @@
       data[kType] = kIsDirectory;
     } else if (S_ISLNK(st.st_mode)) {
       data[kType] = kIsLink;
+    } else if (S_ISSOCK(st.st_mode)) {
+      data[kType] = kIsSock;
+    } else if (S_ISFIFO(st.st_mode)) {
+      data[kType] = kIsPipe;
     } else {
       data[kType] = kDoesNotExist;
     }
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index 92ca3a4..93065b0 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -389,18 +389,17 @@
   if (S_ISLNK(entry_info.st_mode)) {
     return File::kIsLink;
   }
+  if (S_ISSOCK(entry_info.st_mode)) {
+    return File::kIsSock;
+  }
+  if (S_ISFIFO(entry_info.st_mode)) {
+    return File::kIsPipe;
+  }
   return File::kDoesNotExist;
 }
 
-static bool CheckTypeAndSetErrno(Namespace* namespc,
-                                 const char* name,
-                                 File::Type expected,
-                                 bool follow_links) {
-  File::Type actual = File::GetType(namespc, name, follow_links);
-  if (actual == expected) {
-    return true;
-  }
-  switch (actual) {
+static void SetErrno(File::Type type) {
+  switch (type) {
     case File::kIsDirectory:
       errno = EISDIR;
       break;
@@ -411,12 +410,27 @@
       errno = EINVAL;
       break;
   }
+}
+
+static bool CheckTypeAndSetErrno(Namespace* namespc,
+                                 const char* name,
+                                 File::Type expected,
+                                 bool follow_links) {
+  File::Type actual = File::GetType(namespc, name, follow_links);
+  if (actual == expected) {
+    return true;
+  }
+  SetErrno(actual);
   return false;
 }
 
 bool File::Delete(Namespace* namespc, const char* name) {
-  return CheckTypeAndSetErrno(namespc, name, kIsFile, true) &&
-         (NO_RETRY_EXPECTED(unlink(name)) == 0);
+  File::Type type = File::GetType(namespc, name, true);
+  if (type == kIsFile || type == kIsSock || type == kIsPipe) {
+    return (NO_RETRY_EXPECTED(unlink(name)) == 0);
+  }
+  SetErrno(type);
+  return false;
 }
 
 bool File::DeleteLink(Namespace* namespc, const char* name) {
@@ -427,8 +441,12 @@
 bool File::Rename(Namespace* namespc,
                   const char* old_path,
                   const char* new_path) {
-  return CheckTypeAndSetErrno(namespc, old_path, kIsFile, true) &&
-         (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0);
+  File::Type type = File::GetType(namespc, old_path, true);
+  if (type == kIsFile || type == kIsSock || type == kIsPipe) {
+    return (NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0);
+  }
+  SetErrno(type);
+  return false;
 }
 
 bool File::RenameLink(Namespace* namespc,
@@ -441,8 +459,12 @@
 bool File::Copy(Namespace* namespc,
                 const char* old_path,
                 const char* new_path) {
-  return CheckTypeAndSetErrno(namespc, old_path, kIsFile, true) &&
-         (copyfile(old_path, new_path, NULL, COPYFILE_ALL) == 0);
+  File::Type type = File::GetType(namespc, old_path, true);
+  if (type == kIsFile || type == kIsSock || type == kIsPipe) {
+    return (copyfile(old_path, new_path, NULL, COPYFILE_ALL) == 0);
+  }
+  SetErrno(type);
+  return false;
 }
 
 static bool StatHelper(Namespace* namespc, const char* name, struct stat* st) {
@@ -480,6 +502,10 @@
       data[kType] = kIsDirectory;
     } else if (S_ISLNK(st.st_mode)) {
       data[kType] = kIsLink;
+    } else if (S_ISSOCK(st.st_mode)) {
+      data[kType] = kIsSock;
+    } else if (S_ISFIFO(st.st_mode)) {
+      data[kType] = kIsPipe;
     } else {
       data[kType] = kDoesNotExist;
     }
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index 0b9ae80..e3b9075 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -16,12 +16,20 @@
 
   static const link = const FileSystemEntityType._internal(2);
 
-  static const notFound = const FileSystemEntityType._internal(3);
+  static const unixDomainSock = const FileSystemEntityType._internal(3);
+
+  static const pipe = const FileSystemEntityType._internal(4);
+
+  static const notFound = const FileSystemEntityType._internal(5);
+  @Deprecated("Use notFound instead")
+  static const NOT_FOUND = notFound;
 
   static const _typeList = const [
     FileSystemEntityType.file,
     FileSystemEntityType.directory,
     FileSystemEntityType.link,
+    FileSystemEntityType.unixDomainSock,
+    FileSystemEntityType.pipe,
     FileSystemEntityType.notFound,
   ];
   final int _type;
@@ -29,7 +37,14 @@
   const FileSystemEntityType._internal(this._type);
 
   static FileSystemEntityType _lookup(int type) => _typeList[type];
-  String toString() => const ['file', 'directory', 'link', 'notFound'][_type];
+  String toString() => const [
+        'file',
+        'directory',
+        'link',
+        'unixDomainSock',
+        'pipe',
+        'notFound'
+      ][_type];
 }
 
 /// The result of calling the POSIX `stat()` function on a file system object.
diff --git a/tests/standalone/io/named_pipe_operations_test.dart b/tests/standalone/io/named_pipe_operations_test.dart
new file mode 100644
index 0000000..1e17dab
--- /dev/null
+++ b/tests/standalone/io/named_pipe_operations_test.dart
@@ -0,0 +1,118 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Testing file input stream, VM-only, standalone test.
+
+import "dart:convert";
+import "dart:io";
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+import "package:path/path.dart";
+
+final String stdinPipePath = '/dev/fd/0';
+
+startProcess(Directory dir, String fname, String script, String result) async {
+  File file = new File(join(dir.path, fname));
+  file.writeAsString(script);
+  StringBuffer output = new StringBuffer();
+  Process process = await Process.start(
+      Platform.executable,
+      []
+        ..addAll(Platform.executableArguments)
+        ..add('--sound-null-safety')
+        ..add('--verbosity=warning')
+        ..add(file.path));
+  bool stdinWriteFailed = false;
+  process.stdout.transform(utf8.decoder).listen(output.write);
+  process.stderr.transform(utf8.decoder).listen((data) {
+    if (!stdinWriteFailed) {
+      Expect.fail(data);
+      process.kill();
+    }
+  });
+  process.stdin.done.catchError((e) {
+    // If the write to stdin fails, then give up. We can't test the thing we
+    // wanted to test.
+    stdinWriteFailed = true;
+    process.kill();
+  });
+  await process.stdin.flush();
+  await process.stdin.close();
+
+  int status = await process.exitCode;
+  if (!stdinWriteFailed) {
+    Expect.equals(0, status);
+    Expect.contains(result, output.toString());
+  }
+}
+
+main() async {
+  asyncStart();
+  // Operations on a named pipe is only supported on Linux and MacOS.
+  if (!Platform.isLinux && !Platform.isMacOS) {
+    print("This test is only supported on Linux and MacOS.");
+    asyncEnd();
+    return;
+  }
+
+  Directory directory = Directory.systemTemp.createTempSync('named_pipe');
+
+  final String delScript = '''
+    import "dart:io";
+    main() {
+      try {
+        final file = File("$stdinPipePath");
+        if (file.existsSync()) print("Pipe Exists");
+        file.deleteSync();
+        if (!file.existsSync()) print("Pipe Deleted");
+      } catch (e) {
+        print(e);
+      }
+    }
+  ''';
+
+  final String renameScript = '''
+    import "dart:io";
+    main() {
+      try {
+        final file = File("$stdinPipePath");
+        if (file.existsSync()) print("Pipe Exists");
+        file.renameSync("junk");
+        if (!file.existsSync()) print("Pipe Renamed");
+      } catch (e) {
+        print(e);
+      }
+    }
+  ''';
+
+  final String copyScript = '''
+    import "dart:io";
+    main() {
+      try {
+        final file = File("$stdinPipePath");
+        if (file.existsSync()) print("Pipe Exists");
+        file.copySync("junk");
+      } catch (e) {
+        print(e);
+      }
+    }
+  ''';
+
+  // If there's no file system access to the pipe, then we can't do a meaningful
+  // test.
+  if (!await (new File(stdinPipePath).exists())) {
+    print("Couldn't find $stdinPipePath.");
+    directory.deleteSync(recursive: true);
+    asyncEnd();
+    return;
+  }
+
+  await startProcess(directory, 'delscript', delScript, "Cannot delete file");
+  await startProcess(
+      directory, 'renamescript', renameScript, "Cannot rename file");
+  await startProcess(directory, 'copyscript', copyScript, "Cannot copy file");
+
+  directory.deleteSync(recursive: true);
+  asyncEnd();
+}
diff --git a/tests/standalone/io/named_pipe_type_test.dart b/tests/standalone/io/named_pipe_type_test.dart
new file mode 100644
index 0000000..4069837
--- /dev/null
+++ b/tests/standalone/io/named_pipe_type_test.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Testing file input stream, VM-only, standalone test.
+
+import "dart:convert";
+import "dart:io";
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+import "package:path/path.dart";
+
+main() async {
+  asyncStart();
+  // Reading a script from a named pipe is only supported on Linux and MacOS.
+  if (!Platform.isLinux && !Platform.isMacOS) {
+    print("This test is only supported on Linux and MacOS.");
+    asyncEnd();
+    return;
+  }
+
+  Directory dir = Directory.systemTemp.createTempSync('named_pipe');
+  final String stdinPipePath = '/dev/fd/0';
+  final String script = '''
+    import "dart:io";
+    main() {
+      FileStat fileStat = FileStat.statSync("$stdinPipePath");
+      print(fileStat.type);
+    }
+  ''';
+  File file = new File(join(dir.path, "typeScript"));
+  file.writeAsString(script);
+
+  // If there's no file system access to the pipe, then we can't do a meaningful
+  // test.
+  if (!await (new File(stdinPipePath).exists())) {
+    print("Couldn't find $stdinPipePath.");
+    dir.deleteSync(recursive: true);
+    asyncEnd();
+    return;
+  }
+
+  StringBuffer output = new StringBuffer();
+  Process process = await Process.start(
+      Platform.executable,
+      []
+        ..addAll(Platform.executableArguments)
+        ..add('--sound-null-safety')
+        ..add('--verbosity=warning')
+        ..add(file.path));
+  bool stdinWriteFailed = false;
+  process.stdout.transform(utf8.decoder).listen(output.write);
+  process.stderr.transform(utf8.decoder).listen((data) {
+    if (!stdinWriteFailed) {
+      Expect.fail(data);
+      process.kill();
+    }
+  });
+  process.stdin.done.catchError((e) {
+    // If the write to stdin fails, then give up. We can't test the thing we
+    // wanted to test.
+    stdinWriteFailed = true;
+    process.kill();
+  });
+  // process.stdin.writeln(script);
+  await process.stdin.flush();
+  await process.stdin.close();
+
+  int status = await process.exitCode;
+  if (!stdinWriteFailed) {
+    Expect.equals(0, status);
+    Expect.equals("pipe\n", output.toString());
+  }
+
+  dir.deleteSync(recursive: true);
+  asyncEnd();
+}
diff --git a/tests/standalone/io/unix_socket_test.dart b/tests/standalone/io/unix_socket_test.dart
index d63011a..e0b80b6 100644
--- a/tests/standalone/io/unix_socket_test.dart
+++ b/tests/standalone/io/unix_socket_test.dart
@@ -553,7 +553,7 @@
               socket.close();
             }
           }), (e, st) {
-    print('Got expected unhandled exception $e $st');
+    // print('Got expected unhandled exception $e $st');
     Expect.equals(true, e is SocketException);
     completer.complete(true);
   });
@@ -823,6 +823,79 @@
   });
 }
 
+Future testDeleteFile(String tempDirPath) async {
+  if (!Platform.isLinux && !Platform.isAndroid) {
+    return;
+  }
+  final name = '$tempDirPath/sock';
+  final address = InternetAddress(name, type: InternetAddressType.unix);
+  var server = await RawServerSocket.bind(address, 0, shared: false);
+  final file = File(name);
+  Expect.isTrue(file.existsSync());
+  Expect.isTrue(await file.exists());
+  file.deleteSync();
+  Expect.isFalse(file.existsSync());
+  Expect.isFalse(await file.exists());
+  await server.close();
+
+  server = await RawServerSocket.bind(address, 0, shared: false);
+  Expect.isTrue(file.existsSync());
+  Expect.isTrue(await file.exists());
+  await file.delete();
+  Expect.isFalse(file.existsSync());
+  Expect.isFalse(await file.exists());
+  await server.close();
+}
+
+Future testFileStat(String tempDirPath) async {
+  if (!Platform.isLinux && !Platform.isAndroid) {
+    return;
+  }
+  final name = '$tempDirPath/sock';
+  final address = InternetAddress(name, type: InternetAddressType.unix);
+  var server = await RawServerSocket.bind(address, 0, shared: false);
+  FileStat fileStat = FileStat.statSync(name);
+  Expect.equals(FileSystemEntityType.unixDomainSock, fileStat.type);
+  await server.close();
+}
+
+Future testFileRename(String tempDirPath) async {
+  if (!Platform.isLinux && !Platform.isAndroid) {
+    return;
+  }
+  final name1 = '$tempDirPath/sock1';
+  final name2 = '$tempDirPath/sock2';
+  final address = InternetAddress(name1, type: InternetAddressType.unix);
+  var server = await RawServerSocket.bind(address, 0, shared: false);
+  final file1 = File(name1);
+  final file2 = file1.renameSync(name2);
+  Expect.isFalse(file1.existsSync());
+  Expect.isTrue(file2.existsSync());
+  await server.close();
+  file2.deleteSync();
+  Expect.isFalse(file1.existsSync());
+  Expect.isFalse(file2.existsSync());
+}
+
+Future testFileCopy(String tempDirPath) async {
+  if (!Platform.isLinux && !Platform.isAndroid) {
+    return;
+  }
+  final name1 = '$tempDirPath/sock1';
+  final name2 = '$tempDirPath/sock2';
+  final address = InternetAddress(name1, type: InternetAddressType.unix);
+  final file1 = File(name1);
+  var server = await RawServerSocket.bind(address, 0, shared: false);
+  try {
+    final file2 = file1.copySync(name2);
+    Expect.isFalse(true);
+  } catch (e) {
+    Expect.isTrue(e is FileSystemException);
+  }
+  await server.close();
+  Expect.isFalse(file1.existsSync());
+}
+
 void main(List<String> args) async {
   runZonedGuarded(() async {
     if (args.length > 0 && args[0] == '--start-stdio-message-test') {
@@ -831,7 +904,6 @@
       });
       return;
     }
-
     await withTempDir('unix_socket_test', (Directory dir) async {
       await testAddress('${dir.path}');
     });
@@ -877,6 +949,18 @@
     await withTempDir('unix_socket_test', (Directory dir) async {
       await testStdioMessage('${dir.path}', caller: true);
     });
+    await withTempDir('unix_socket_test', (Directory dir) async {
+      await testDeleteFile('${dir.path}');
+    });
+    await withTempDir('unix_socket_test', (Directory dir) async {
+      await testFileStat('${dir.path}');
+    });
+    await withTempDir('unix_socket_test', (Directory dir) async {
+      await testFileRename('${dir.path}');
+    });
+    await withTempDir('unix_socket_test', (Directory dir) async {
+      await testFileCopy('${dir.path}');
+    });
   }, (e, st) {
     if (Platform.isMacOS || Platform.isLinux || Platform.isAndroid) {
       Expect.fail("Unexpected exception $e is thrown");
diff --git a/tests/standalone/standalone_precompiled.status b/tests/standalone/standalone_precompiled.status
index 69da5e9..2e1b2fb 100644
--- a/tests/standalone/standalone_precompiled.status
+++ b/tests/standalone/standalone_precompiled.status
@@ -19,7 +19,9 @@
 io/http_response_deadline_test: Skip
 io/http_server_close_response_after_error_test: Skip
 io/https_unauthorized_test: Skip
+io/named_pipe_operations_test: Skip
 io/named_pipe_script_test: Skip
+io/named_pipe_type_test: Skip
 io/namespace_test: Skip # Issue 33168
 io/platform_resolved_executable_test: Skip
 io/print_sync_test: Skip
diff --git a/tests/standalone/standalone_vm.status b/tests/standalone/standalone_vm.status
index 067e3e05..5933938 100644
--- a/tests/standalone/standalone_vm.status
+++ b/tests/standalone/standalone_vm.status
@@ -56,7 +56,6 @@
 
 [ $mode == release && $runtime == vm && $system == macos ]
 io/http_server_close_response_after_error_test: Pass, Timeout # Issue 28370: timeout.
-io/named_pipe_script_test: Pass, RuntimeError # Issue 28737
 
 [ $mode == release && $runtime == vm && $system == windows ]
 io/http_server_close_response_after_error_test: Pass, Timeout # Issue 28370: timeout.
@@ -64,6 +63,9 @@
 [ $runtime == dart_precompiled && $system == linux && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 || $arch == x64) ]
 io/stdout_stderr_non_blocking_test: Pass, Timeout # Issue 35192
 
+[ $runtime == vm && $system == macos ]
+io/named_pipe_script_test: Pass, RuntimeError # Issue 28737
+
 [ $runtime == vm && ($arch == arm || $arch == arm64) ]
 io/dart_std_io_pipe_test: Timeout, Pass
 io/file_input_stream_test: Skip # Issue 26109
diff --git a/tests/standalone_2/io/named_pipe_operations_test.dart b/tests/standalone_2/io/named_pipe_operations_test.dart
new file mode 100644
index 0000000..1e17dab
--- /dev/null
+++ b/tests/standalone_2/io/named_pipe_operations_test.dart
@@ -0,0 +1,118 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Testing file input stream, VM-only, standalone test.
+
+import "dart:convert";
+import "dart:io";
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+import "package:path/path.dart";
+
+final String stdinPipePath = '/dev/fd/0';
+
+startProcess(Directory dir, String fname, String script, String result) async {
+  File file = new File(join(dir.path, fname));
+  file.writeAsString(script);
+  StringBuffer output = new StringBuffer();
+  Process process = await Process.start(
+      Platform.executable,
+      []
+        ..addAll(Platform.executableArguments)
+        ..add('--sound-null-safety')
+        ..add('--verbosity=warning')
+        ..add(file.path));
+  bool stdinWriteFailed = false;
+  process.stdout.transform(utf8.decoder).listen(output.write);
+  process.stderr.transform(utf8.decoder).listen((data) {
+    if (!stdinWriteFailed) {
+      Expect.fail(data);
+      process.kill();
+    }
+  });
+  process.stdin.done.catchError((e) {
+    // If the write to stdin fails, then give up. We can't test the thing we
+    // wanted to test.
+    stdinWriteFailed = true;
+    process.kill();
+  });
+  await process.stdin.flush();
+  await process.stdin.close();
+
+  int status = await process.exitCode;
+  if (!stdinWriteFailed) {
+    Expect.equals(0, status);
+    Expect.contains(result, output.toString());
+  }
+}
+
+main() async {
+  asyncStart();
+  // Operations on a named pipe is only supported on Linux and MacOS.
+  if (!Platform.isLinux && !Platform.isMacOS) {
+    print("This test is only supported on Linux and MacOS.");
+    asyncEnd();
+    return;
+  }
+
+  Directory directory = Directory.systemTemp.createTempSync('named_pipe');
+
+  final String delScript = '''
+    import "dart:io";
+    main() {
+      try {
+        final file = File("$stdinPipePath");
+        if (file.existsSync()) print("Pipe Exists");
+        file.deleteSync();
+        if (!file.existsSync()) print("Pipe Deleted");
+      } catch (e) {
+        print(e);
+      }
+    }
+  ''';
+
+  final String renameScript = '''
+    import "dart:io";
+    main() {
+      try {
+        final file = File("$stdinPipePath");
+        if (file.existsSync()) print("Pipe Exists");
+        file.renameSync("junk");
+        if (!file.existsSync()) print("Pipe Renamed");
+      } catch (e) {
+        print(e);
+      }
+    }
+  ''';
+
+  final String copyScript = '''
+    import "dart:io";
+    main() {
+      try {
+        final file = File("$stdinPipePath");
+        if (file.existsSync()) print("Pipe Exists");
+        file.copySync("junk");
+      } catch (e) {
+        print(e);
+      }
+    }
+  ''';
+
+  // If there's no file system access to the pipe, then we can't do a meaningful
+  // test.
+  if (!await (new File(stdinPipePath).exists())) {
+    print("Couldn't find $stdinPipePath.");
+    directory.deleteSync(recursive: true);
+    asyncEnd();
+    return;
+  }
+
+  await startProcess(directory, 'delscript', delScript, "Cannot delete file");
+  await startProcess(
+      directory, 'renamescript', renameScript, "Cannot rename file");
+  await startProcess(directory, 'copyscript', copyScript, "Cannot copy file");
+
+  directory.deleteSync(recursive: true);
+  asyncEnd();
+}
diff --git a/tests/standalone_2/io/named_pipe_type_test.dart b/tests/standalone_2/io/named_pipe_type_test.dart
new file mode 100644
index 0000000..4069837
--- /dev/null
+++ b/tests/standalone_2/io/named_pipe_type_test.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Testing file input stream, VM-only, standalone test.
+
+import "dart:convert";
+import "dart:io";
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+import "package:path/path.dart";
+
+main() async {
+  asyncStart();
+  // Reading a script from a named pipe is only supported on Linux and MacOS.
+  if (!Platform.isLinux && !Platform.isMacOS) {
+    print("This test is only supported on Linux and MacOS.");
+    asyncEnd();
+    return;
+  }
+
+  Directory dir = Directory.systemTemp.createTempSync('named_pipe');
+  final String stdinPipePath = '/dev/fd/0';
+  final String script = '''
+    import "dart:io";
+    main() {
+      FileStat fileStat = FileStat.statSync("$stdinPipePath");
+      print(fileStat.type);
+    }
+  ''';
+  File file = new File(join(dir.path, "typeScript"));
+  file.writeAsString(script);
+
+  // If there's no file system access to the pipe, then we can't do a meaningful
+  // test.
+  if (!await (new File(stdinPipePath).exists())) {
+    print("Couldn't find $stdinPipePath.");
+    dir.deleteSync(recursive: true);
+    asyncEnd();
+    return;
+  }
+
+  StringBuffer output = new StringBuffer();
+  Process process = await Process.start(
+      Platform.executable,
+      []
+        ..addAll(Platform.executableArguments)
+        ..add('--sound-null-safety')
+        ..add('--verbosity=warning')
+        ..add(file.path));
+  bool stdinWriteFailed = false;
+  process.stdout.transform(utf8.decoder).listen(output.write);
+  process.stderr.transform(utf8.decoder).listen((data) {
+    if (!stdinWriteFailed) {
+      Expect.fail(data);
+      process.kill();
+    }
+  });
+  process.stdin.done.catchError((e) {
+    // If the write to stdin fails, then give up. We can't test the thing we
+    // wanted to test.
+    stdinWriteFailed = true;
+    process.kill();
+  });
+  // process.stdin.writeln(script);
+  await process.stdin.flush();
+  await process.stdin.close();
+
+  int status = await process.exitCode;
+  if (!stdinWriteFailed) {
+    Expect.equals(0, status);
+    Expect.equals("pipe\n", output.toString());
+  }
+
+  dir.deleteSync(recursive: true);
+  asyncEnd();
+}
diff --git a/tests/standalone_2/io/unix_socket_test.dart b/tests/standalone_2/io/unix_socket_test.dart
index 228552a..7d8e7a5 100644
--- a/tests/standalone_2/io/unix_socket_test.dart
+++ b/tests/standalone_2/io/unix_socket_test.dart
@@ -552,7 +552,7 @@
               socket.close();
             }
           }), (e, st) {
-    print('Got expected unhandled exception $e $st');
+    // print('Got expected unhandled exception $e $st');
     Expect.equals(true, e is SocketException);
     completer.complete(true);
   });
@@ -825,6 +825,79 @@
   return completer.future;
 }
 
+Future testDeleteFile(String tempDirPath) async {
+  if (!Platform.isLinux && !Platform.isAndroid) {
+    return;
+  }
+  final address =
+      InternetAddress('$tempDirPath/sock', type: InternetAddressType.unix);
+  var server = await RawServerSocket.bind(address, 0, shared: false);
+  final file = File('$tempDirPath/sock');
+  Expect.isTrue(file.existsSync());
+  Expect.isTrue(await file.exists());
+  file.deleteSync();
+  Expect.isFalse(file.existsSync());
+  Expect.isFalse(await file.exists());
+  await server.close();
+
+  server = await RawServerSocket.bind(address, 0, shared: false);
+  Expect.isTrue(file.existsSync());
+  Expect.isTrue(await file.exists());
+  await file.delete();
+  Expect.isFalse(file.existsSync());
+  Expect.isFalse(await file.exists());
+  await server.close();
+}
+
+Future testFileStat(String tempDirPath) async {
+  if (!Platform.isLinux && !Platform.isAndroid) {
+    return;
+  }
+  final name = '$tempDirPath/sock';
+  final address = InternetAddress(name, type: InternetAddressType.unix);
+  var server = await RawServerSocket.bind(address, 0, shared: false);
+  FileStat fileStat = FileStat.statSync(name);
+  Expect.equals(FileSystemEntityType.unixDomainSock, fileStat.type);
+  server.close();
+}
+
+Future testFileRename(String tempDirPath) async {
+  if (!Platform.isLinux && !Platform.isAndroid) {
+    return;
+  }
+  final name1 = '$tempDirPath/sock1';
+  final name2 = '$tempDirPath/sock2';
+  final address = InternetAddress(name1, type: InternetAddressType.unix);
+  var server = await RawServerSocket.bind(address, 0, shared: false);
+  final file1 = File(name1);
+  final file2 = file1.renameSync(name2);
+  Expect.isFalse(file1.existsSync());
+  Expect.isTrue(file2.existsSync());
+  await server.close();
+  file2.deleteSync();
+  Expect.isFalse(file1.existsSync());
+  Expect.isFalse(file2.existsSync());
+}
+
+Future testFileCopy(String tempDirPath) async {
+  if (!Platform.isLinux && !Platform.isAndroid) {
+    return;
+  }
+  final name1 = '$tempDirPath/sock1';
+  final name2 = '$tempDirPath/sock2';
+  final address = InternetAddress(name1, type: InternetAddressType.unix);
+  final file1 = File(name1);
+  var server = await RawServerSocket.bind(address, 0, shared: false);
+  try {
+    final file2 = file1.copySync(name2);
+    Expect.isFalse(true);
+  } catch (e) {
+    Expect.isTrue(e is FileSystemException);
+  }
+  await server.close();
+  Expect.isFalse(file1.existsSync());
+}
+
 void main(List<String> args) async {
   runZonedGuarded(() async {
     if (args.length > 0 && args[0] == '--start-stdio-message-test') {
@@ -879,6 +952,18 @@
     await withTempDir('unix_socket_test', (Directory dir) async {
       await testStdioMessage('${dir.path}', caller: true);
     });
+    await withTempDir('unix_socket_test', (Directory dir) async {
+      await testDeleteFile('${dir.path}');
+    });
+    await withTempDir('unix_socket_test', (Directory dir) async {
+      await testFileStat('${dir.path}');
+    });
+    await withTempDir('unix_socket_test', (Directory dir) async {
+      await testFileRename('${dir.path}');
+    });
+    await withTempDir('unix_socket_test', (Directory dir) async {
+      await testFileCopy('${dir.path}');
+    });
   }, (e, st) {
     if (Platform.isMacOS || Platform.isLinux || Platform.isAndroid) {
       Expect.fail("Unexpected exception $e is thrown");
diff --git a/tests/standalone_2/standalone_2_precompiled.status b/tests/standalone_2/standalone_2_precompiled.status
index f7f7eb2..69f6510 100644
--- a/tests/standalone_2/standalone_2_precompiled.status
+++ b/tests/standalone_2/standalone_2_precompiled.status
@@ -16,7 +16,9 @@
 io/http_response_deadline_test: Skip
 io/http_server_close_response_after_error_test: Skip
 io/https_unauthorized_test: Skip
+io/named_pipe_operations_test: Skip
 io/named_pipe_script_test: Skip
+io/named_pipe_type_test: Skip
 io/namespace_test: Skip # Issue 33168
 io/platform_resolved_executable_test: Skip
 io/print_sync_test: Skip
diff --git a/tests/standalone_2/standalone_2_vm.status b/tests/standalone_2/standalone_2_vm.status
index 067e3e05..5933938 100644
--- a/tests/standalone_2/standalone_2_vm.status
+++ b/tests/standalone_2/standalone_2_vm.status
@@ -56,7 +56,6 @@
 
 [ $mode == release && $runtime == vm && $system == macos ]
 io/http_server_close_response_after_error_test: Pass, Timeout # Issue 28370: timeout.
-io/named_pipe_script_test: Pass, RuntimeError # Issue 28737
 
 [ $mode == release && $runtime == vm && $system == windows ]
 io/http_server_close_response_after_error_test: Pass, Timeout # Issue 28370: timeout.
@@ -64,6 +63,9 @@
 [ $runtime == dart_precompiled && $system == linux && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64 || $arch == x64) ]
 io/stdout_stderr_non_blocking_test: Pass, Timeout # Issue 35192
 
+[ $runtime == vm && $system == macos ]
+io/named_pipe_script_test: Pass, RuntimeError # Issue 28737
+
 [ $runtime == vm && ($arch == arm || $arch == arm64) ]
 io/dart_std_io_pipe_test: Timeout, Pass
 io/file_input_stream_test: Skip # Issue 26109
diff --git a/tools/VERSION b/tools/VERSION
index eee5da8..5b795aa 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 115
+PRERELEASE 116
 PRERELEASE_PATCH 0
\ No newline at end of file