* BinaryReader.cs: Fixed line endings.
[mono.git] / mcs / class / corlib / System.IO / Path.cs
index 4174d98858124b9e4418becb0e856aa0f3dbf3a9..ca1a18ff9028ae629c08483739158eff292e83d3 100644 (file)
@@ -38,6 +38,7 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
+using System.Globalization;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Security;
@@ -51,7 +52,7 @@ namespace System.IO {
        [ComVisible (true)]
        public static class Path {
 
-               [Obsolete ("see GetInvalidPathChars and GetInvalidfileNameChars methods.")]
+               [Obsolete ("see GetInvalidPathChars and GetInvalidFileNameChars methods.")]
                public static readonly char[] InvalidPathChars;
 #else
        public sealed class Path {
@@ -259,7 +260,6 @@ namespace System.IO {
 
                        // if the supplied path ends with a separator...
                        char end = path [path.Length - 1];
-                       bool end_dsc = ((end == DirectorySeparatorChar) || (end == AltDirectorySeparatorChar));
 
                        if (path.Length >= 2 &&
                                IsDsc (path [0]) &&
@@ -286,7 +286,7 @@ namespace System.IO {
                        }
 
                        // if the original ended with a [Alt]DirectorySeparatorChar then ensure the full path also ends with one
-                       if (end_dsc && (path [path.Length - 1] != DirectorySeparatorChar))
+                       if (IsDsc (end) && (path [path.Length - 1] != DirectorySeparatorChar))
                                path += DirectorySeparatorChar;
 
                        return path;
@@ -323,11 +323,16 @@ namespace System.IO {
                                        // UNC: \\server or \\server\share
                                        // Get server
                                        while (len < path.Length && !IsDsc (path [len])) len++;
+
                                        // Get share
-                                       while (len < path.Length && !IsDsc (path [len])) len++;
+                                       if (len < path.Length) {
+                                               len++;
+                                               while (len < path.Length && !IsDsc (path [len])) len++;
+                                       }
+
                                        return DirectorySeparatorStr +
                                                DirectorySeparatorStr +
-                                               path.Substring (2).Replace (AltDirectorySeparatorChar, DirectorySeparatorChar);
+                                               path.Substring (2, len - 2).Replace (AltDirectorySeparatorChar, DirectorySeparatorChar);
                                } else if (IsDsc (path [0])) {
                                        // path starts with '\' or '/'
                                        return DirectorySeparatorStr;
@@ -353,10 +358,11 @@ namespace System.IO {
                        do {
                                num = rnd.Next ();
                                num++;
-                               path = Path.Combine (GetTempPath(), "tmp" + num.ToString("x"));
+                               path = Path.Combine (GetTempPath(), "tmp" + num.ToString("x") + ".tmp");
 
                                try {
-                                       f = new FileStream (path, FileMode.CreateNew);
+                                       f = new FileStream (path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read,
+                                                           8192, false, (FileOptions) 1);
                                }
                                catch (SecurityException) {
                                        // avoid an endless loop
@@ -424,10 +430,10 @@ namespace System.IO {
                {
                        // return a new array as we do not want anyone to be able to change the values
                        if (Environment.IsRunningOnWindows) {
-                               return new char [36] { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+                               return new char [36] { '\x22', '\x3C', '\x3E', '\x7C', '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
                                        '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\x10', '\x11', '\x12', 
                                        '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D', 
-                                       '\x1E', '\x1F', '\x22', '\x3C', '\x3E', '\x7C' };
+                                       '\x1E', '\x1F' };
                        } else {
                                return new char [1] { '\x00' };
                        }
@@ -445,7 +451,7 @@ namespace System.IO {
                                int i = 0;
                                rng.GetNonZeroBytes (buffer);
                                while ((i < buffer.Length) && (sb.Length < 12)) {
-                                       char c = (char)i;
+                                       char c = (char) buffer [i];
                                        if (Array.IndexOf (invalid, c) == -1)
                                                sb.Append (c);
                                        i++;
@@ -502,65 +508,108 @@ namespace System.IO {
                        dirEqualsVolume = (DirectorySeparatorChar == VolumeSeparatorChar);
                }
                
-               
-               static string CanonicalizePath (string path) {
-                       
+               static bool SameRoot (string root, string path)
+               {
+                       // compare root - if enough details are available
+                       if ((root.Length < 2) || (path.Length < 2))
+                               return false;
+                       // same volume/drive
+                       if (!root [0].Equals (path [0]))
+                               return false;
+                       // presence if the separator
+                       if (path[1] != Path.VolumeSeparatorChar)
+                               return false;
+                       if ((root.Length > 2) && (path.Length > 2)) {
+                               // but don't directory compare the directory separator
+                               return (IsDsc (root[2]) && IsDsc (path[2]));
+                       }
+                       return true;
+               }
+
+               static string CanonicalizePath (string path)
+               {
                        // STEP 1: Check for empty string
-                       if (path == null) return path;
+                       if (path == null)
+                               return path;
                        if (Environment.IsRunningOnWindows)
                                path = path.Trim ();
 
-                       if (path == String.Empty) return path;
-                       
+                       if (path.Length == 0)
+                               return path;
+
                        // STEP 2: Check to see if this is only a root
-                       string root = GetPathRoot (path);
+                       string root = Path.GetPathRoot (path);
                        // it will return '\' for path '\', while it should return 'c:\' or so.
                        // Note: commenting this out makes the ened for the (target == 1...) check in step 5
                        //if (root == path) return path;
-                               
+
                        // STEP 3: split the directories, this gets rid of consecutative "/"'s
-                       string [] dirs = path.Split (DirectorySeparatorChar, AltDirectorySeparatorChar);
+                       string[] dirs = path.Split (Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
                        // STEP 4: Get rid of directories containing . and ..
                        int target = 0;
-                       
+
                        for (int i = 0; i < dirs.Length; i++) {
-                               if (dirs [i] == "." || (i != 0 && dirs [i] == String.Empty)) continue;
-                               else if (dirs [i] == "..") {
-                                       if (target != 0) target--;
-                               }
-                               else
-                                       dirs [target++] = dirs [i];
+                               if (dirs[i] == "." || (i != 0 && dirs[i].Length == 0))
+                                       continue;
+                               else if (dirs[i] == "..") {
+                                       if (target != 0)
+                                               target--;
+                               } else
+                                       dirs[target++] = dirs[i];
                        }
 
                        // STEP 5: Combine everything.
-                       if (target == 0 || (target == 1 && dirs [0] == ""))
+                       if (target == 0 || (target == 1 && dirs[0] == ""))
                                return root;
                        else {
                                string ret = String.Join (DirectorySeparatorStr, dirs, 0, target);
-                               switch (DirectorySeparatorChar) {
-                               case '\\': // Windows
+                               if (Environment.IsRunningOnWindows) {
+                                       if (!SameRoot (root, ret))
+                                               ret = root + ret;
                                        // In GetFullPath(), it is assured that here never comes UNC. So this must only applied to such path that starts with '\', without drive specification.
-                                       if (path [0] != DirectorySeparatorChar && path.StartsWith (root)) {
+                                       if (!IsDsc (path[0]) && SameRoot (root, path)) {
                                                if (ret.Length <= 2 && !ret.EndsWith (DirectorySeparatorStr)) // '\' after "c:"
-                                                       ret += DirectorySeparatorChar;
+                                                       ret += Path.DirectorySeparatorChar;
                                                return ret;
                                        } else {
                                                string current = Directory.GetCurrentDirectory ();
-                                               if (current.Length > 1 && current [1] == VolumeSeparatorChar) {
+                                               if (current.Length > 1 && current[1] == Path.VolumeSeparatorChar) {
                                                        // DOS local file path
-                                                       if (ret.Length == 0 || IsDsc (ret [0]))
+                                                       if (ret.Length == 0 || IsDsc (ret[0]))
                                                                ret += '\\';
                                                        return current.Substring (0, 2) + ret;
-                                               }
-                                               else if (IsDsc (current [current.Length - 1]) && IsDsc (ret [0]))
+                                               } else if (IsDsc (current[current.Length - 1]) && IsDsc (ret[0]))
                                                        return current + ret.Substring (1);
                                                else
                                                        return current + ret;
                                        }
-                               default: // Unix/Mac
-                                       return ret;
                                }
+                               return ret;
+                       }
+               }
+
+               // required for FileIOPermission (and most proibably reusable elsewhere too)
+               // both path MUST be "full paths"
+               static internal bool IsPathSubsetOf (string subset, string path)
+               {
+                       if (subset.Length > path.Length)
+                               return false;
+
+                       // check that everything up to the last separator match
+                       int slast = subset.LastIndexOfAny (PathSeparatorChars);
+                       if (String.Compare (subset, 0, path, 0, slast) != 0)
+                               return false;
+
+                       slast++;
+                       // then check if the last segment is identical
+                       int plast = path.IndexOfAny (PathSeparatorChars, slast);
+                       if (plast >= slast) {
+                               return String.Compare (subset, slast, path, slast, path.Length - plast) == 0;
                        }
+                       if (subset.Length != path.Length)
+                               return false;
+
+                       return String.Compare (subset, slast, path, slast, subset.Length - slast) == 0;
                }
        }
 }