Unverified Commit 788c8b8a authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

[flutter_tools] tool exit access denied during symlinking (#106213)

parent 9f4b9bfd
...@@ -1004,20 +1004,32 @@ void createPluginSymlinks(FlutterProject project, {bool force = false, @visibleF ...@@ -1004,20 +1004,32 @@ void createPluginSymlinks(FlutterProject project, {bool force = false, @visibleF
void handleSymlinkException(FileSystemException e, { void handleSymlinkException(FileSystemException e, {
required Platform platform, required Platform platform,
required OperatingSystemUtils os, required OperatingSystemUtils os,
required String destination,
required String source,
}) { }) {
if (platform.isWindows && (e.osError?.errorCode ?? 0) == 1314) { if (platform.isWindows) {
final String? versionString = RegExp(r'[\d.]+').firstMatch(os.name)?.group(0); // ERROR_ACCESS_DENIED
final Version? version = Version.parse(versionString); if (e.osError?.errorCode == 5) {
// Windows 10 14972 is the oldest version that allows creating symlinks throwToolExit(
// just by enabling developer mode; before that it requires running the 'ERROR_ACCESS_DENIED file system exception thrown while trying to '
// terminal as Administrator. 'create a symlink from $source to $destination',
// https://blogs.windows.com/windowsdeveloper/2016/12/02/symlinks-windows-10/ );
final String instructions = (version != null && version >= Version(10, 0, 14972)) }
? 'Please enable Developer Mode in your system settings. Run\n' // ERROR_PRIVILEGE_NOT_HELD, user cannot symlink
' start ms-settings:developers\n' if (e.osError?.errorCode == 1314) {
'to open settings.' final String? versionString = RegExp(r'[\d.]+').firstMatch(os.name)?.group(0);
: 'You must build from a terminal run as administrator.'; final Version? version = Version.parse(versionString);
throwToolExit('Building with plugins requires symlink support.\n\n$instructions'); // Windows 10 14972 is the oldest version that allows creating symlinks
// just by enabling developer mode; before that it requires running the
// terminal as Administrator.
// https://blogs.windows.com/windowsdeveloper/2016/12/02/symlinks-windows-10/
final String instructions = (version != null && version >= Version(10, 0, 14972))
? 'Please enable Developer Mode in your system settings. Run\n'
' start ms-settings:developers\n'
'to open settings.'
: 'You must build from a terminal run as administrator.';
throwToolExit('Building with plugins requires symlink support.\n\n$instructions');
}
} }
} }
...@@ -1043,7 +1055,13 @@ void _createPlatformPluginSymlinks(Directory symlinkDirectory, List<Object?>? pl ...@@ -1043,7 +1055,13 @@ void _createPlatformPluginSymlinks(Directory symlinkDirectory, List<Object?>? pl
try { try {
link.createSync(path); link.createSync(path);
} on FileSystemException catch (e) { } on FileSystemException catch (e) {
handleSymlinkException(e, platform: globals.platform, os: globals.os); handleSymlinkException(
e,
platform: globals.platform,
os: globals.os,
destination: 'dest',
source: 'source',
);
rethrow; rethrow;
} }
} }
......
...@@ -84,6 +84,8 @@ void main() { ...@@ -84,6 +84,8 @@ void main() {
// using it instead of fs must re-run any necessary setup (e.g., // using it instead of fs must re-run any necessary setup (e.g.,
// setUpProject). // setUpProject).
late FileSystem fsWindows; late FileSystem fsWindows;
const String pubCachePath = '/path/to/.pub-cache/hosted/pub.dartlang.org/foo-1.2.3';
const String ephemeralPackagePath = '/path/to/app/linux/flutter/ephemeral/foo-1.2.3';
// Adds basic properties to the flutterProject and its subprojects. // Adds basic properties to the flutterProject and its subprojects.
void setUpProject(FileSystem fileSystem) { void setUpProject(FileSystem fileSystem) {
...@@ -1612,8 +1614,36 @@ flutter: ...@@ -1612,8 +1614,36 @@ flutter:
const FileSystemException e = FileSystemException('', '', OSError('', 1314)); const FileSystemException e = FileSystemException('', '', OSError('', 1314));
expect(() => handleSymlinkException(e, platform: platform, os: os), expect(
throwsToolExit(message: 'start ms-settings:developers')); () => handleSymlinkException(
e,
platform: platform,
os: os,
source: pubCachePath,
destination: ephemeralPackagePath,
),
throwsToolExit(message: 'start ms-settings:developers'),
);
});
testWithoutContext('Symlink ERROR_ACCESS_DENIED failures show developers paths that were used', () async {
final Platform platform = FakePlatform(operatingSystem: 'windows');
final FakeOperatingSystemUtils os = FakeOperatingSystemUtils('Microsoft Windows [Version 10.0.14972.1]');
const FileSystemException e = FileSystemException('', '', OSError('', 5));
expect(
() => handleSymlinkException(
e,
platform: platform,
os: os,
source: pubCachePath,
destination: ephemeralPackagePath,
),
throwsToolExit(
message: 'ERROR_ACCESS_DENIED file system exception thrown while trying to create a symlink from $pubCachePath to $ephemeralPackagePath',
),
);
}); });
testWithoutContext('Symlink failures instruct developers to run as administrator on older versions of Windows', () async { testWithoutContext('Symlink failures instruct developers to run as administrator on older versions of Windows', () async {
...@@ -1622,8 +1652,16 @@ flutter: ...@@ -1622,8 +1652,16 @@ flutter:
const FileSystemException e = FileSystemException('', '', OSError('', 1314)); const FileSystemException e = FileSystemException('', '', OSError('', 1314));
expect(() => handleSymlinkException(e, platform: platform, os: os), expect(
throwsToolExit(message: 'administrator')); () => handleSymlinkException(
e,
platform: platform,
os: os,
source: pubCachePath,
destination: ephemeralPackagePath,
),
throwsToolExit(message: 'administrator'),
);
}); });
testWithoutContext('Symlink failures only give instructions for specific errors', () async { testWithoutContext('Symlink failures only give instructions for specific errors', () async {
...@@ -1632,7 +1670,16 @@ flutter: ...@@ -1632,7 +1670,16 @@ flutter:
const FileSystemException e = FileSystemException('', '', OSError('', 999)); const FileSystemException e = FileSystemException('', '', OSError('', 999));
expect(() => handleSymlinkException(e, platform: platform, os: os), returnsNormally); expect(
() => handleSymlinkException(
e,
platform: platform,
os: os,
source: pubCachePath,
destination: ephemeralPackagePath,
),
returnsNormally,
);
}); });
}); });
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment