Merge pull request #819 from brendanzagaeski/patch-1
[mono.git] / mcs / class / corlib / System.IO / Path.cs
index 5b63ce725058477d59e1003d6c58c52de6bba550..217f5af3992db30931b28c8ca4d709857bfc226c 100644 (file)
@@ -222,6 +222,8 @@ namespace System.IO {
 
                                if (l >= 2 && DirectorySeparatorChar == '\\' && ret [l - 1] == VolumeSeparatorChar)
                                        return ret + DirectorySeparatorChar;
+                               else if (l == 1 && DirectorySeparatorChar == '\\' && path.Length >= 2 && path [nLast] == VolumeSeparatorChar)
+                                       return ret + VolumeSeparatorChar;
                                else {
                                        //
                                        // Important: do not use CanonicalizePath here, use
@@ -287,6 +289,29 @@ namespace System.IO {
                        return fullpath;
                }
 
+               // http://msdn.microsoft.com/en-us/library/windows/desktop/aa364963%28v=vs.85%29.aspx
+               [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+               private static extern int GetFullPathName(string path, int numBufferChars, StringBuilder buffer, ref IntPtr lpFilePartOrNull); 
+
+               internal static string GetFullPathName(string path)
+               {
+                       const int MAX_PATH = 260;
+                       StringBuilder buffer = new StringBuilder(MAX_PATH);
+                       IntPtr ptr = IntPtr.Zero;
+                       int length = GetFullPathName(path, MAX_PATH, buffer, ref ptr);
+                       if (length == 0)
+                       {
+                               int error = Marshal.GetLastWin32Error();
+                               throw new IOException("Windows API call to GetFullPathName failed, Windows error code: " + error);
+                       }
+                       else if (length > MAX_PATH)
+                       {
+                               buffer = new StringBuilder(length);
+                               GetFullPathName(path, length, buffer, ref ptr);
+                       }
+                       return buffer.ToString();
+               }
+
                internal static string WindowsDriveAdjustment (string path)
                {
                        // two special cases to consider when a drive is specified
@@ -295,14 +320,14 @@ namespace System.IO {
                        if ((path [1] != ':') || !Char.IsLetter (path [0]))
                                return path;
 
-                       string current = Directory.GetCurrentDirectory ();
+                       string current = Directory.InsecureGetCurrentDirectory ();
                        // first, only the drive is specified
                        if (path.Length == 2) {
                                // then if the current directory is on the same drive
                                if (current [0] == path [0])
                                        path = current; // we return it
                                else
-                                       path += '\\';
+                                       path = GetFullPathName(path); // we have to use the GetFullPathName Windows API
                        } else if ((path [2] != Path.DirectorySeparatorChar) && (path [2] != Path.AltDirectorySeparatorChar)) {
                                // second, the drive + a directory is specified *without* a separator between them (e.g. C:dir).
                                // If the current directory is on the specified drive...
@@ -310,8 +335,8 @@ namespace System.IO {
                                        // then specified directory is appended to the current drive directory
                                        path = Path.Combine (current, path.Substring (2, path.Length - 2));
                                } else {
-                                       // if not, then just pretend there was a separator (Path.Combine won't work in this case)
-                                       path = String.Concat (path.Substring (0, 2), DirectorySeparatorStr, path.Substring (2, path.Length - 2));
+                                       // we have to use the GetFullPathName Windows API
+                                       path = GetFullPathName(path);
                                }
                        }
                        return path;
@@ -357,17 +382,17 @@ namespace System.IO {
                                                }
                                                canonicalize = start > 0;
                                        }
-                                       
-                                       path = Directory.GetCurrentDirectory () + DirectorySeparatorStr + path;
+
+                                       path = Directory.InsecureGetCurrentDirectory() + DirectorySeparatorStr + path;
                                } else if (DirectorySeparatorChar == '\\' &&
                                        path.Length >= 2 &&
                                        IsDsc (path [0]) &&
                                        !IsDsc (path [1])) { // like `\abc\def'
-                                       string current = Directory.GetCurrentDirectory ();
+                                       string current = Directory.InsecureGetCurrentDirectory();
                                        if (current [1] == VolumeSeparatorChar)
                                                path = current.Substring (0, 2) + path;
                                        else
-                                               path = current.Substring (0, current.IndexOf ('\\', current.IndexOf ("\\\\") + 1));
+                                               path = current.Substring (0, current.IndexOf ('\\', current.IndexOfOrdinalUnchecked ("\\\\") + 1));
                                }
                        }
                        
@@ -460,6 +485,10 @@ namespace System.IO {
                                        if (ex.hresult != MonoIO.FileAlreadyExistsHResult || count ++ > 65536)
                                                throw;
                                }
+                               catch (UnauthorizedAccessException ex) {
+                                       if (count ++ > 65536)
+                                               throw new IOException (ex.Message, ex);
+                               }
                        } while (f == null);
                        
                        f.Close();
@@ -712,6 +741,9 @@ namespace System.IO {
                                                else
                                                        return current + ret;
                                        }
+                               } else {
+                                       if (root != "" && ret.Length > 0 && ret [0] != '/')
+                                               ret = root + ret;
                                }
                                return ret;
                        }
@@ -741,7 +773,7 @@ namespace System.IO {
                        return String.Compare (subset, slast, path, slast, subset.Length - slast) == 0;
                }
 
-#if NET_4_0 || MOONLIGHT || MOBILE
+#if NET_4_0
                public
 #else
                 internal
@@ -755,13 +787,21 @@ namespace System.IO {
                        var ret = new StringBuilder ();
                        int pathsLen = paths.Length;
                        int slen;
+                       need_sep = false;
+
                        foreach (var s in paths) {
-                               need_sep = false;
                                if (s == null)
                                        throw new ArgumentNullException ("One of the paths contains a null value", "paths");
+                               if (s.Length == 0)
+                                       continue;
                                if (s.IndexOfAny (InvalidPathChars) != -1)
                                        throw new ArgumentException ("Illegal characters in path.");
-                               
+
+                               if (need_sep) {
+                                       need_sep = false;
+                                       ret.Append (DirectorySeparatorStr);
+                               }
+
                                pathsLen--;
                                if (IsPathRooted (s))
                                        ret.Length = 0;
@@ -773,15 +813,12 @@ namespace System.IO {
                                        if (p1end != DirectorySeparatorChar && p1end != AltDirectorySeparatorChar && p1end != VolumeSeparatorChar)
                                                need_sep = true;
                                }
-                               
-                               if (need_sep)
-                                       ret.Append (DirectorySeparatorStr);
                        }
 
                        return ret.ToString ();
                }
 
-#if NET_4_0 || MOONLIGHT || MOBILE
+#if NET_4_0
                public
 #else
                 internal
@@ -800,7 +837,7 @@ namespace System.IO {
                        return Combine (new string [] { path1, path2, path3 });
                }
 
-#if NET_4_0 || MOONLIGHT || MOBILE
+#if NET_4_0
                public
 #else
                 internal
@@ -840,11 +877,6 @@ namespace System.IO {
                                if (idx >= 0 && idx != 1)
                                        throw new ArgumentException (parameterName);
                        }
-#if MOONLIGHT
-                       // On Moonlight (SL4+) there are some limitations in "Elevated Trust"
-                       if (SecurityManager.HasElevatedPermissions) {
-                       }
-#endif
                }
        }
 }