Skip to content

Commit 15a0089

Browse files
brianquinlanCommit Queue
authored andcommitted
Add the ability to copy pipes using File.Copy
Bug:#60999 Change-Id: I2e20ad5c051b43582483d5275d6d2b65b6f3395a Tested: unit Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/439823 Commit-Queue: Brian Quinlan <[email protected]> Reviewed-by: Alexander Aprelev <[email protected]>
1 parent c87169e commit 15a0089

File tree

3 files changed

+33
-1
lines changed

3 files changed

+33
-1
lines changed

runtime/bin/file_linux.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,10 @@ bool File::Copy(Namespace* namespc,
494494
// From sendfile man pages:
495495
// Applications may wish to fall back to read(2)/write(2) in the case
496496
// where sendfile() fails with EINVAL or ENOSYS.
497-
if ((result < 0) && ((errno == EINVAL) || (errno == ENOSYS))) {
497+
//
498+
// Also, fallback on ESPIPE (returned when the input file is not seekable).
499+
if ((result < 0) &&
500+
((errno == EINVAL) || (errno == ENOSYS) || (errno == ESPIPE))) {
498501
const intptr_t kBufferSize = 8 * KB;
499502
uint8_t* buffer = reinterpret_cast<uint8_t*>(malloc(kBufferSize));
500503
while ((result = TEMP_FAILURE_RETRY(read(old_fd, buffer, kBufferSize))) >

runtime/bin/file_macos.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,8 @@ bool File::Copy(Namespace* namespc,
489489
const char* new_path) {
490490
File::Type type = File::GetType(namespc, old_path, true);
491491
if (type == kIsFile || type == kIsSock || type == kIsPipe) {
492+
// `copyfile` will complete with [ENOTSUP] if the source file is:
493+
// "...not a directory, symbolic link, or regular file."
492494
return (copyfile(old_path, new_path, nullptr, COPYFILE_ALL) == 0);
493495
}
494496
SetErrno(type);

tests/standalone/io/file_copy_test.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,39 @@
55
// Dart test program for testing File.copy*
66

77
import 'dart:io';
8+
import 'dart:ffi' as ffi;
89

910
import "package:expect/async_helper.dart";
1011
import "package:expect/expect.dart";
12+
import 'package:ffi/ffi.dart';
1113

1214
const FILE_CONTENT1 = 'some string';
1315
const FILE_CONTENT2 = 'some other string';
1416

17+
@ffi.Native<ffi.Int Function(ffi.Pointer<ffi.Char>, ffi.Int)>()
18+
external int mkfifo(ffi.Pointer<ffi.Char> pathname, int mode);
19+
20+
void testFifo() async {
21+
var tmp = Directory.systemTemp.createTempSync('copy-fifo');
22+
if (!Platform.isLinux) {
23+
return;
24+
}
25+
26+
using((arena) {
27+
// 432 => rw-rw----
28+
if (mkfifo("${tmp.path}/fifo".toNativeUtf8(allocator: arena).cast(), 432) ==
29+
-1) {
30+
throw FileSystemException('error creating FIFO');
31+
}
32+
});
33+
34+
final write = File("${tmp.path}/fifo").writeAsString("Hello World!");
35+
final copy = File("${tmp.path}/fifo").copy("${tmp.path}/copy");
36+
await Future.wait([write, copy]);
37+
Expect.equals("Hello World!", File("${tmp.path}/copy").readAsStringSync());
38+
tmp.deleteSync(recursive: true);
39+
}
40+
1541
void testCopySync() {
1642
var tmp = Directory.systemTemp.createTempSync('dart-file-copy');
1743

@@ -115,6 +141,7 @@ void testCopy() {
115141
main() {
116142
testCopySync();
117143
testCopy();
144+
testFifo();
118145
// This is Windows only test.
119146
testWithForwardSlashes();
120147
}

0 commit comments

Comments
 (0)