[vm/file] Ensure that appropriate type is reported for links to files vs directories
Bug: https://github.com/dart-lang/sdk/issues/30410
Change-Id: I96c9ca8a5aff4a4337022047ea0b844335efdfcf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/161260
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Zichang Guo <zichangguo@google.com>
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index 848036a..21f8df2 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -886,15 +886,22 @@
result = kDoesNotExist;
} else if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
if (follow_links) {
- HANDLE dir_handle =
+ HANDLE target_handle =
CreateFileW(name.wide(), 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- if (dir_handle == INVALID_HANDLE_VALUE) {
+ if (target_handle == INVALID_HANDLE_VALUE) {
result = File::kIsLink;
} else {
- CloseHandle(dir_handle);
- result = File::kIsDirectory;
+ BY_HANDLE_FILE_INFORMATION info;
+ if (!GetFileInformationByHandle(target_handle, &info)) {
+ CloseHandle(target_handle);
+ return File::kIsLink;
+ }
+ CloseHandle(target_handle);
+ return ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ ? File::kIsDirectory
+ : File::kIsFile;
}
} else {
result = kIsLink;
diff --git a/tests/standalone/io/windows_file_system_links_test.dart b/tests/standalone/io/windows_file_system_links_test.dart
index ccf38e5..dcbc571 100644
--- a/tests/standalone/io/windows_file_system_links_test.dart
+++ b/tests/standalone/io/windows_file_system_links_test.dart
@@ -2,9 +2,9 @@
// 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.
-import 'package:expect/expect.dart';
import "dart:io";
-import "dart:isolate";
+
+import 'package:expect/expect.dart';
testJunctionTypeDelete() {
var temp =
@@ -75,9 +75,57 @@
});
}
+void testLinkToFile() {
+ final temp =
+ Directory.systemTemp.createTempSync('dart_windows_file_system_links');
+ // Create file
+ File file = new File(temp.path + Platform.pathSeparator + "test-file.tmp");
+ file.createSync();
+ // Create link pointing to the file above
+ Link link = new Link(temp.path + Platform.pathSeparator + "test-link.lnk");
+ link.createSync(file.path);
+
+ Link link2 = new Link(temp.path + Platform.pathSeparator + "test-link2.lnk");
+ link2.createSync(link.path);
+
+ try {
+ Expect.isTrue(FileSystemEntity.isLinkSync(link.path));
+ Expect.isTrue(FileSystemEntity.isLinkSync(link2.path));
+ Expect.isTrue(FileSystemEntity.isFileSync(link2.path));
+ Expect.isFalse(FileSystemEntity.isDirectorySync(link2.path));
+ } finally {
+ temp.deleteSync(recursive: true);
+ }
+}
+
+void testLinkToDirectory() {
+ final temp =
+ Directory.systemTemp.createTempSync('dart_windows_file_system_links');
+ // Create file
+ Directory dir = Directory(temp.path + Platform.pathSeparator + "test-dir");
+ dir.createSync();
+ // Create link pointing to the file above
+ Link link = Link(temp.path + Platform.pathSeparator + "test-link.lnk");
+ link.createSync(dir.path);
+
+ Link link2 = Link(temp.path + Platform.pathSeparator + "test-link2.lnk");
+ link2.createSync(link.path);
+
+ try {
+ Expect.isTrue(FileSystemEntity.isLinkSync(link.path));
+ Expect.isTrue(FileSystemEntity.isLinkSync(link2.path));
+ Expect.isFalse(FileSystemEntity.isFileSync(link2.path));
+ Expect.isTrue(FileSystemEntity.isDirectorySync(link2.path));
+ } finally {
+ temp.deleteSync(recursive: true);
+ }
+}
+
main() {
// Links on other platforms are tested by file_system_[async_]links_test.
if (Platform.operatingSystem == 'windows') {
testJunctionTypeDelete();
+ testLinkToFile();
+ testLinkToDirectory();
}
}
diff --git a/tests/standalone_2/io/windows_file_system_links_test.dart b/tests/standalone_2/io/windows_file_system_links_test.dart
index ccf38e5..dcbc571 100644
--- a/tests/standalone_2/io/windows_file_system_links_test.dart
+++ b/tests/standalone_2/io/windows_file_system_links_test.dart
@@ -2,9 +2,9 @@
// 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.
-import 'package:expect/expect.dart';
import "dart:io";
-import "dart:isolate";
+
+import 'package:expect/expect.dart';
testJunctionTypeDelete() {
var temp =
@@ -75,9 +75,57 @@
});
}
+void testLinkToFile() {
+ final temp =
+ Directory.systemTemp.createTempSync('dart_windows_file_system_links');
+ // Create file
+ File file = new File(temp.path + Platform.pathSeparator + "test-file.tmp");
+ file.createSync();
+ // Create link pointing to the file above
+ Link link = new Link(temp.path + Platform.pathSeparator + "test-link.lnk");
+ link.createSync(file.path);
+
+ Link link2 = new Link(temp.path + Platform.pathSeparator + "test-link2.lnk");
+ link2.createSync(link.path);
+
+ try {
+ Expect.isTrue(FileSystemEntity.isLinkSync(link.path));
+ Expect.isTrue(FileSystemEntity.isLinkSync(link2.path));
+ Expect.isTrue(FileSystemEntity.isFileSync(link2.path));
+ Expect.isFalse(FileSystemEntity.isDirectorySync(link2.path));
+ } finally {
+ temp.deleteSync(recursive: true);
+ }
+}
+
+void testLinkToDirectory() {
+ final temp =
+ Directory.systemTemp.createTempSync('dart_windows_file_system_links');
+ // Create file
+ Directory dir = Directory(temp.path + Platform.pathSeparator + "test-dir");
+ dir.createSync();
+ // Create link pointing to the file above
+ Link link = Link(temp.path + Platform.pathSeparator + "test-link.lnk");
+ link.createSync(dir.path);
+
+ Link link2 = Link(temp.path + Platform.pathSeparator + "test-link2.lnk");
+ link2.createSync(link.path);
+
+ try {
+ Expect.isTrue(FileSystemEntity.isLinkSync(link.path));
+ Expect.isTrue(FileSystemEntity.isLinkSync(link2.path));
+ Expect.isFalse(FileSystemEntity.isFileSync(link2.path));
+ Expect.isTrue(FileSystemEntity.isDirectorySync(link2.path));
+ } finally {
+ temp.deleteSync(recursive: true);
+ }
+}
+
main() {
// Links on other platforms are tested by file_system_[async_]links_test.
if (Platform.operatingSystem == 'windows') {
testJunctionTypeDelete();
+ testLinkToFile();
+ testLinkToDirectory();
}
}