Fix Path.GetFullPath for roots on Windows
authorJosh Peterson <petersonjm1@gmail.com>
Fri, 15 Apr 2016 17:04:27 +0000 (13:04 -0400)
committerJonathan Chambers <joncham@gmail.com>
Wed, 13 Jul 2016 13:54:11 +0000 (09:54 -0400)
On Windows, xbuild can fail with the somewhat obscure error message: "error : Error building target GetReferenceAssemblyPaths: UNC paths should be of the form \\server\share." This occurs because a call to Path.GetFullPath(@"\") returns the string "\" on Windows, when it should return a root path that includes the drive letter, like "C:\".

The code in xbuild tries to scan directories for files. Specifically, it looks for "\.*dll". If any .dll files exist in the root directory, each will be returned with the path "/\foo.dll". This path is used to create a FileInfo, and the exception about a UNC path occurs.

So if the path is "\" or "/" Path.GetFullPath should return the correct root path, including the drive letter, on Windows.

Here is the full call stack from xbuild:

Error building target GetReferenceAssemblyPaths: System.ArgumentException: UNC paths should be of the form \\server\share.
at System.IO.Path.InsecureGetFullPath (System.String path) <0x25343f0 + 0x003fb> in <filename unknown>:0
at System.IO.Path.GetFullPath (System.String path) <0x2534378 + 0x00013> in <filename unknown>:0
at System.IO.FileInfo..ctor (System.String fileName) <0x25fae20 + 0x00033> in <filename unknown>:0
at (wrapper remoting-invoke-with-check) System.IO.FileInfo:.ctor (string)
at System.IO.DirectoryInfo.GetFiles (System.String searchPattern) <0x25fa7c0 + 0x00087> in <filename unknown>:0
at (wrapper remoting-invoke-with-check) System.IO.DirectoryInfo:GetFiles (string)
input, Int32 ptr, System.IO.DirectoryInfo directory, Boolean recursive) <0x25fa2b0 + 0x0016b> in <filename unknown>:0
input, Int32 ptr, System.IO.DirectoryInfo directory) <0x25fa270 + 0x0002f> in <filename unknown>:0
at Microsoft.Build.BuildEngine.DirectoryScanner.ProcessInclude (ITaskItem include_item, System.Collections.Generic.Dictionary`2 excludedItems, System.Collections.Generic.List`1 includedItems) <0x25d72d0 + 0x002ab> in <filename unknown>:0
at Microsoft.Build.BuildEngine.DirectoryScanner.Scan () <0x25d70e0 + 0x000ff> in <filename unknown>:0
at Microsoft.Build.BuildEngine.BuildItem.Evaluate (Microsoft.Build.BuildEngine.Project project, Boolean evaluatedTo) <0x25d5a50 + 0x005d3> in <filename unknown>:0
at Microsoft.Build.BuildEngine.BuildTaskItem.Execute () <0x25e5ad8 + 0x0002b> in <filename unknown>:0
at Microsoft.Build.BuildEngine.TaskBatchingImpl.Execute (IBuildTask buildTask, TaskExecutionMode taskExecutionMode) <0x25e3698 + 0x0004a> in <filename unknown>:0
at Microsoft.Build. BuildEngine.TaskBatchingImpl.Run (IBuildTask buildTask, TaskExecutionMode taskExecutionMode, System.Boolean& executeOnErrors) <0x25e50e0 + 0x0004f> in <filename unknown>:0
at Microsoft.Build.BuildEngine.TaskBatchingImpl.Build (IBuildTask buildTask, TaskExecutionMode taskExecutionMode, System.Boolean& executeOnErrors) <0x25e21b0 + 0x00097> in <filename unknown>:0
at Microsoft.Build.BuildEngine.TargetBatchingImpl.RunTargetWithBucket (System.Collections.Generic.Dictionary`2 bucket, Microsoft.Build.BuildEngine.Target target, System.Boolean& executeOnErrors) <0x25e14b8 + 0x00213> in <filename unknown>:0
at Microsoft.Build.BuildEngine.TargetBatchingImpl.Run (Microsoft.Build.BuildEngine.Target target, System.Boolean& executeOnErrors) <0x25e1360 + 0x000f7> in <filename unknown>:0
at Microsoft.Build.BuildEngine.TargetBatchingImpl.Build (Microsoft.Build.BuildEngine.Target target, System.Boolean& executeOnErrors) <0x25dfee0 + 0x00053> in <filename unknown>:0
at Microsoft.Build.BuildEngine.Target.DoBuild (System.Boolean& executeOnErrors) <0x25dfcf0 + 0x0004f> in <filename unknown>:0

mcs/class/corlib/System.IO/Path.cs
mcs/class/corlib/Test/System.IO/PathTest.cs

index fc62a4db6e3bff42240dfdca7c37c83252c7e266..0b2704c1202c9246308dc56342c5c56edaa44f60 100644 (file)
@@ -320,7 +320,9 @@ namespace System.IO {
 
                internal static string WindowsDriveAdjustment (string path)
                {
-                       // two special cases to consider when a drive is specified
+                       // three special cases to consider when a drive is specified
+                       if (path == @"\" || path == "/")
+                               return Path.GetPathRoot(Directory.GetCurrentDirectory());
                        if (path.Length < 2)
                                return path;
                        if ((path [1] != ':') || !Char.IsLetter (path [0]))
index 897342eba7f20d6483be863287879c2b469029e1..c3ab9935350c9b1f3071960bda46d06d97b74d81 100644 (file)
@@ -688,6 +688,11 @@ namespace MonoTests.System.IO
                                                i, root + test [i, 0], ex.GetType ()));
                                }
                        }
+
+                       // These cases require that we don't pass a root to GetFullPath - it should return the proper drive root.
+                       string root4 = Path.GetPathRoot(Directory.GetCurrentDirectory());
+                       Assert.AreEqual(root4, Path.GetFullPath(@"\"));
+                       Assert.AreEqual(root4, Path.GetFullPath("/"));
                }
 
                [Test]