Properly handle symlinked source files in hot mode (#5978)

diff --git a/packages/flutter_tools/lib/src/devfs.dart b/packages/flutter_tools/lib/src/devfs.dart
index 4c515d0..6874461 100644
--- a/packages/flutter_tools/lib/src/devfs.dart
+++ b/packages/flutter_tools/lib/src/devfs.dart
@@ -30,7 +30,7 @@
   final AssetBundleEntry bundleEntry;
   String get assetPath => bundleEntry.archivePath;
 
-  final File file;
+  final FileSystemEntity file;
   FileStat _fileStat;
   // When we scanned for files, did this still exist?
   bool _exists = false;
@@ -69,15 +69,29 @@
     if (_isSourceEntry)
       return;
     _fileStat = file.statSync();
+    if (_fileStat.type == FileSystemEntityType.LINK) {
+      // Stat the link target.
+      String resolved = file.resolveSymbolicLinksSync();
+      _fileStat = FileStat.statSync(resolved);
+    }
   }
 
   bool get _isSourceEntry => file == null;
 
   bool get _isAssetEntry => bundleEntry != null;
 
+  File _getFile() {
+    if (file is Link) {
+      // The link target.
+      return new File(file.resolveSymbolicLinksSync());
+    }
+    return file;
+  }
+
   Future<List<int>> contentsAsBytes() async {
     if (_isSourceEntry)
       return bundleEntry.contentsAsBytes();
+    final File file = _getFile();
     return file.readAsBytes();
   }
 
@@ -86,6 +100,7 @@
       return new Stream<List<int>>.fromIterable(
           <List<int>>[bundleEntry.contentsAsBytes()]);
     }
+    final File file = _getFile();
     return file.openRead();
   }
 
@@ -417,7 +432,7 @@
     logger.flush();
   }
 
-  void _scanFile(String devicePath, File file) {
+  void _scanFile(String devicePath, FileSystemEntity file) {
     DevFSEntry entry = _entries[devicePath];
     if (entry == null) {
       // New file.
@@ -485,10 +500,20 @@
       Stream<FileSystemEntity> files =
           directory.list(recursive: recursive, followLinks: false);
       await for (FileSystemEntity file in files) {
-        if (file is! File) {
+        if (file is Link) {
+          final String linkPath = file.resolveSymbolicLinksSync();
+          final FileSystemEntityType linkType =
+              FileStat.statSync(linkPath).type;
+          if (linkType == FileSystemEntityType.DIRECTORY) {
+            // Skip links to directories.
+            continue;
+          }
+        }
+        if (file is Directory) {
           // Skip non-files.
           continue;
         }
+        assert((file is Link) || (file is File));
         if (ignoreDotFiles && path.basename(file.path).startsWith('.')) {
           // Skip dot files.
           continue;