Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(909)

Unified Diff: sdk/lib/_internal/pub/lib/src/io.dart

Issue 15047005: Fix canonicalize(). (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | sdk/lib/_internal/pub/lib/src/path_source.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/_internal/pub/lib/src/io.dart
diff --git a/sdk/lib/_internal/pub/lib/src/io.dart b/sdk/lib/_internal/pub/lib/src/io.dart
index 0e2a93210469b742a4a13a4b6a26178950f77f70..46e525509ca126309868b25d1211082c0c547eed 100644
--- a/sdk/lib/_internal/pub/lib/src/io.dart
+++ b/sdk/lib/_internal/pub/lib/src/io.dart
@@ -6,6 +6,7 @@
library pub.io;
import 'dart:async';
+import 'dart:collection';
import 'dart:io';
import 'dart:isolate';
import 'dart:json';
@@ -48,12 +49,74 @@ bool fileExists(String file) => new File(file).existsSync();
/// filesystem; nonexistent or unreadable path entries are treated as normal
/// directories.
String canonicalize(String pathString) {
- var components = path.split(path.normalize(path.absolute(pathString)));
- var newPath = components.removeAt(0);
- // Rebuild the path one level at a time, resolving the symlinks for each level
- // in turn.
- for (var component in components) {
- newPath = resolveLink(path.join(newPath, component));
+ var seen = new Set<String>();
Bob Nystrom 2013/05/07 23:16:36 Wow. Nasty but at least it's very well documented.
nweiz 2013/05/07 23:19:14 I thought about that, but right now pathos is very
+ var components = new Queue<String>.from(
+ path.split(path.normalize(path.absolute(pathString))));
+
+ // The canonical path, built incrementally as we iterate through [components].
+ var newPath = components.removeFirst();
+
+ // Move through the components of the path, resolving each one's symlinks as
+ // necessary. A resolved component may also add new components that need to be
+ // resolved in turn.
+ while (!components.isEmpty) {
+ seen.add(path.join(newPath, path.joinAll(components)));
+ var resolvedPath = resolveLink(
+ path.join(newPath, components.removeFirst()));
+ var relative = path.relative(resolvedPath, from: newPath);
+
+ // If the resolved path of the component relative to `newPath` is just ".",
+ // that means component was a symlink pointing to its parent directory. We
+ // can safely ignore such components.
+ if (relative == '.') continue;
+
+ var relativeComponents = new Queue<String>.from(path.split(relative));
+
+ // If the resolved path is absolute relative to `newPath`, that means it's
+ // on a different drive. We need to canonicalize the entire target of that
+ // symlink again.
+ if (path.isAbsolute(relative)) {
+ // If we've already tried to canonicalize the new path, we've encountered
+ // a symlink loop. Avoid going infinite by treating the recursive symlink
+ // as the canonical path.
+ if (seen.contains(relative)) {
+ newPath = relative;
+ } else {
+ newPath = relativeComponents.removeFirst();
+ relativeComponents.addAll(components);
+ components = relativeComponents;
+ }
+ continue;
+ }
+
+ // Pop directories off `newPath` if the component links upwards in the
+ // directory hierarchy.
+ while (relativeComponents.first == '..') {
+ newPath = path.dirname(newPath);
+ relativeComponents.removeFirst();
+ }
+
+ // If there's only one component left, [resolveLink] guarantees that it's
+ // not a link (or is a broken link). We can just add it to `newPath` and
+ // continue resolving the remaining components.
+ if (relativeComponents.length == 1) {
+ newPath = path.join(newPath, relativeComponents.single);
+ continue;
+ }
+
+ // If we've already tried to canonicalize the new path, we've encountered a
+ // symlink loop. Avoid going infinite by treating the recursive symlink as
+ // the canonical path.
+ var newSubPath = path.join(newPath, path.joinAll(relativeComponents));
+ if (seen.contains(newSubPath)) {
+ newPath = newSubPath;
+ continue;
+ }
+
+ // If there are multiple new components to resolve, add them to the
+ // beginning of the queue.
Bob Nystrom 2013/05/07 23:16:36 beginning -> end
nweiz 2013/05/07 23:19:14 They're actually added to the beginning, since the
+ relativeComponents.addAll(components);
+ components = relativeComponents;
}
return newPath;
}
« no previous file with comments | « no previous file | sdk/lib/_internal/pub/lib/src/path_source.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698