diff --git a/lib/src/io.dart b/lib/src/io.dart index 0af650bda17e36943bffb7cebc344503f6bb4bbb..a7bbb3aba34cf10b82efd667b8c0be542bdbdabf 100644 --- a/lib/src/io.dart +++ b/lib/src/io.dart @@ -33,7 +33,7 @@ bool entryExists(String path) => /// Returns whether [link] exists on the file system. This will return `true` /// for any symlink, regardless of what it points at or whether it's broken. -bool linkExists(String path) => new Link(path).existsSync(); +bool linkExists(String link) => new Link(link).existsSync(); /// Returns whether [file] exists on the file system. This will return `true` /// for a symlink only if that symlink is unbroken and points to a file. @@ -146,7 +146,15 @@ List<String> listDir(String dir, {bool recursive: false, log.io("Listing directory $dir."); var children = []; - for (var entity in new Directory(dir).listSync()) { + for (var entity in new Directory(dir).listSync(followLinks: false)) { + // TODO(nweiz): remove this when issue 4928 is fixed. + if (entity is Link) { + var link = entity.path; + // We treat broken symlinks as files, in that we don't want to recurse + // into them. + entity = dirExists(link) ? new Directory(link) : new File(link); + } + if (entity is File) { var file = entity.path; if (!includeHiddenFiles && path.basename(file).startsWith('.')) { diff --git a/test/io_test.dart b/test/io_test.dart index cc8eb9dbc56b04e2e0c6ec65f71d7798fac5bcde..cd276bc4241b772a0fceec94ee0dffbd68b3b0f0 100644 --- a/test/io_test.dart +++ b/test/io_test.dart @@ -119,6 +119,20 @@ main() { ])); }), completes); }); + + test('treats a broken symlink as a file', () { + expect(withTempDir((temp) { + writeTextFile(path.join(temp, 'file1.txt'), ''); + createDir(path.join(temp, 'dir')); + createSymlink(path.join(temp, 'dir'), path.join(temp, 'linkdir')); + deleteEntry(path.join(temp, 'dir')); + + expect(listDir(temp, recursive: true), unorderedEquals([ + path.join(temp, 'file1.txt'), + path.join(temp, 'linkdir') + ])); + }), completes); + }); }); testExistencePredicate("entryExists", entryExists,