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