[bcl] Remove the ValueAdd and InetAccess NUnit categories (#2212)
[mono.git] / mcs / class / corlib / System.Security.Permissions / FileIOPermission.cs
index 8113954f2030a3c8d81d195623f6c4526bde8cf4..c08313b278fd1ee0bd9a4425621eb3014f573494 100644 (file)
@@ -1,16 +1,12 @@
-//------------------------------------------------------------------------------\r
-// \r
-// System.Security.Permissions.FileIOPermission.cs \r
-//\r
-// Copyright (C) 2001 Nick Drochak, All Rights Reserved\r
-// \r
-// Author:         Nick Drochak, ndrochak@gol.com\r
-// Created:        2002-01-09 \r
-//\r
-//------------------------------------------------------------------------------\r
-
+// 
+// System.Security.Permissions.FileIOPermission.cs 
 //
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Authors:
+//     Nick Drochak, ndrochak@gol.com
+//     Sebastien Pouliot  <sebastien@ximian.com>
+//
+// Copyright (C) 2001 Nick Drochak, All Rights Reserved
+// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-\r
-using System.Collections;\r
-using System.IO;\r
-using System.Text;\r
-\r
-namespace System.Security.Permissions {\r
-\r
-       [Serializable]\r
-       public sealed class FileIOPermission\r
-                : CodeAccessPermission, IBuiltInPermission, IUnrestrictedPermission {\r
-\r
-               private static char[] m_badCharacters = {'\"','<', '>', '|', '*', '?'};\r
-               private bool m_Unrestricted = false;\r
-               private Hashtable m_PathList = new Hashtable();\r
-               private FileIOPermissionAccess m_AllFilesAccess = FileIOPermissionAccess.NoAccess;\r
-               private FileIOPermissionAccess m_AllLocalFilesAccess = FileIOPermissionAccess.NoAccess;\r
-\r
-               public FileIOPermission(PermissionState state) {\r
-                       if (!Enum.IsDefined(typeof(PermissionState), state)){\r
-                               throw new ArgumentException("Invalid permission state.", "state");\r
-                       }\r
-                       m_Unrestricted = (PermissionState.Unrestricted == state);\r
-                       if (m_Unrestricted) {\r
-                               m_AllFilesAccess = FileIOPermissionAccess.AllAccess;\r
-                               m_AllLocalFilesAccess = FileIOPermissionAccess.AllAccess;\r
-                       }\r
-               }\r
-\r
-               public FileIOPermission(FileIOPermissionAccess access, string path)
+
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using System.Runtime.InteropServices;
+using System.Security.AccessControl;
+
+namespace System.Security.Permissions {
+
+       [ComVisible (true)]
+       [Serializable]
+       public sealed class FileIOPermission
+                : CodeAccessPermission, IBuiltInPermission, IUnrestrictedPermission {
+
+               private const int version = 1;
+
+               private static char[] BadPathNameCharacters;
+               private static char[] BadFileNameCharacters;
+
+               static FileIOPermission ()
+               {
+                       // we keep a local (static) copies to avoid calls/allocations
+                       BadPathNameCharacters = Path.GetInvalidPathChars ();
+                       BadFileNameCharacters = Path.GetInvalidFileNameChars ();
+               }
+
+               private bool m_Unrestricted = false;
+               private FileIOPermissionAccess m_AllFilesAccess = FileIOPermissionAccess.NoAccess;
+               private FileIOPermissionAccess m_AllLocalFilesAccess = FileIOPermissionAccess.NoAccess;
+               private ArrayList readList;
+               private ArrayList writeList;
+               private ArrayList appendList;
+               private ArrayList pathList;
+
+               public FileIOPermission (PermissionState state)
+               {
+                       if (CheckPermissionState (state, true) == PermissionState.Unrestricted) {
+                               m_Unrestricted = true;
+                               m_AllFilesAccess = FileIOPermissionAccess.AllAccess;
+                               m_AllLocalFilesAccess = FileIOPermissionAccess.AllAccess;
+                       }
+                       CreateLists ();
+               }
+
+               public FileIOPermission (FileIOPermissionAccess access, string path)
                {
                        if (path == null)
                                throw new ArgumentNullException ("path");
-\r
-                       if ((FileIOPermissionAccess.AllAccess & access) != access){\r
-                               throw new ArgumentException("Illegal enum value: "+access.ToString()+".");\r
-                       }\r
-\r
-                       if (path.LastIndexOfAny(m_badCharacters) >= 0){\r
-                               throw new ArgumentException("Illegal characters found in input.  Security checks can not contain wild card characters.", "path");\r
-                       }\r
-                       \r
-                       AddPathList(access, path);\r
-               }\r
-\r
-               public FileIOPermission(FileIOPermissionAccess access, string[] pathList)
-               {\r
+
+                       CreateLists ();
+                       // access and path will be validated in AddPathList
+                       AddPathList (access, path);
+               }
+
+               public FileIOPermission (FileIOPermissionAccess access, string[] pathList)
+               {
                        if (pathList == null)
                                throw new ArgumentNullException ("pathList");
 
-                       if ((FileIOPermissionAccess.AllAccess & access) != access){\r
-                               throw new ArgumentException("Illegal enum value: "+access.ToString()+".");\r
-                       }\r
-\r
-                       AddPathList(access, pathList);\r
-               }\r
-\r
-               public FileIOPermissionAccess AllFiles {\r
-                       get {\r
-                               return m_AllFilesAccess;\r
-                       } \r
-                       set {\r
-                               // if we are already set to unrestricted, don't change this property\r
-                               if (!m_Unrestricted){\r
-                                       m_AllFilesAccess = value;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               public FileIOPermissionAccess AllLocalFiles {\r
-                       get {\r
-                               return m_AllLocalFilesAccess;\r
-                       } \r
-                       set {\r
-                               // if we are already set to unrestricted, don't change this property\r
-                               if (!m_Unrestricted){\r
-                                       m_AllLocalFilesAccess = value;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               public void AddPathList(FileIOPermissionAccess access, string path){\r
-                       if ((FileIOPermissionAccess.AllAccess & access) != access){\r
-                               throw new ArgumentException("Illegal enum value: {0}.",access.ToString());\r
-                       }\r
-\r
-                       if (path.LastIndexOfAny(m_badCharacters) >= 0){\r
-                               throw new ArgumentException("Invalid characters in path: '{0}'", path);\r
-                       }\r
-\r
-                       // LAMESPEC: docs don't say it must be a rooted path, but the MS implementation enforces it, so we will too.\r
-                       if(!Path.IsPathRooted(path)) {\r
-                               throw new ArgumentException("Absolute path information is required.");\r
-                       }\r
-\r
-                       // don't add the same path twice, instead overwrite access entry for that path\r
-                       if (m_PathList.ContainsKey(path)) {\r
-                               FileIOPermissionAccess currentPermission = (FileIOPermissionAccess)m_PathList[path];\r
-                               currentPermission |= access;\r
-                               m_PathList[path] = currentPermission;\r
-                       }\r
-                       else {\r
-                               m_PathList.Add(path, access);\r
-                       }\r
-               }\r
-\r
-               public void AddPathList(FileIOPermissionAccess access, string[] pathList        ){\r
-                       foreach(string path in pathList){\r
-                               AddPathList(access, path);\r
-                       }\r
-                       \r
-               }\r
-\r
-               // private constructor used by Copy() method\r
-               private FileIOPermission(Hashtable pathList, FileIOPermissionAccess allFiles, \r
-                                               FileIOPermissionAccess allLocalFiles, bool unrestricted){\r
-                       m_PathList = pathList;\r
-                       m_AllFilesAccess = allFiles;\r
-                       m_AllLocalFilesAccess = allLocalFiles;\r
-                       m_Unrestricted = unrestricted;\r
-               }\r
-\r
-               public override IPermission Copy(){\r
-                       if (m_Unrestricted) {\r
-                               return new FileIOPermission(PermissionState.Unrestricted);\r
-                       }\r
-                       else{\r
-                               FileIOPermission retVal = new FileIOPermission(m_PathList, m_AllFilesAccess, m_AllLocalFilesAccess, m_Unrestricted);\r
-                               return retVal;\r
-                       }\r
-               }\r
-\r
-               /*  XML Schema for FileIOPermission\r
-                               <IPermission class=\94FileIOPermission\94 \r
-                                                                version=\941\94\r
-                                                                (\r
-                                                                Read=\94[list of files or folders]\94 | \r
-                                                                Write=\94[list of files or folders]\94 |\r
-                                                                Append=\94[list of files or folders]\94   \r
-                                                                ) v Unrestricted=\94true\94 \r
-                                                                />\r
-               */\r
-               public override void FromXml(SecurityElement esd){\r
-                       if (null == esd) {\r
-                               throw new ArgumentNullException();\r
-                       }\r
-                       if (esd.Tag != "IPermission" || (string)esd.Attributes["class"] != "FileIOPermission"\r
-                                       || (string)esd.Attributes["version"] != "1"){\r
-                               throw new ArgumentException("Not a valid permission element");\r
-                       }\r
-                       m_PathList.Clear();\r
-                       if ("true" == (string)esd.Attributes["Unrestricted"]){\r
-                               m_Unrestricted = true;\r
-                       }\r
-                       else{\r
-                               m_Unrestricted = false;\r
-                               string fileList;\r
-                               fileList = (string)esd.Attributes["Read"];\r
-                               string[] files;\r
-                               if (fileList != null){\r
-                                       files = fileList.Split(';');\r
-                                       AddPathList(FileIOPermissionAccess.Read, files);\r
-                               }\r
-                               fileList = (string)esd.Attributes["Write"];\r
-                               if (fileList != null){\r
-                                       files = fileList.Split(';');\r
-                                       AddPathList(FileIOPermissionAccess.Write, files);\r
-                               }\r
-                               fileList = (string)esd.Attributes["Append"];\r
-                               if (fileList != null){\r
-                                       files = fileList.Split(';');\r
-                                       AddPathList(FileIOPermissionAccess.Append, files);\r
-                               }\r
-                       }\r
-               }\r
-\r
-               public string[] GetPathList(FileIOPermissionAccess access){\r
-                       //LAMESPEC: docs says it returns (semicolon separated) list, but return\r
-                       //type is array.  I think docs are wrong and it just returns an array\r
-                       if ((FileIOPermissionAccess.AllAccess & access) != access){\r
-                               throw new ArgumentException("Illegal enum value: "+access.ToString()+".");\r
-                       }\r
-\r
-                       ArrayList matchingPaths = new ArrayList();\r
-                       System.Collections.IDictionaryEnumerator pathListIterator = m_PathList.GetEnumerator();\r
-                       while (pathListIterator.MoveNext()) {\r
-                               if (((FileIOPermissionAccess)pathListIterator.Value & access) != 0) {\r
-                                       matchingPaths.Add((string)pathListIterator.Key);\r
-                               }\r
-                       }\r
-                       if (matchingPaths.Count == 0) {\r
-                               return null;\r
-                       }\r
-                       else {\r
-                               return (string[])matchingPaths.ToArray(typeof(string));\r
-                       }\r
-               }\r
-\r
-               public override IPermission Intersect(IPermission target){ \r
-                       if (null == target){\r
-                               return null;\r
-                       }\r
-                       else {\r
-                               if (target.GetType() != typeof(FileIOPermission)){\r
-                                       throw new ArgumentException();\r
-                               }\r
-                       }\r
-                       FileIOPermission FIOPTarget = (FileIOPermission)target;\r
-                       if (FIOPTarget.IsUnrestricted() && m_Unrestricted){\r
-                               return new FileIOPermission(PermissionState.Unrestricted);\r
-                       }\r
-                       else if (FIOPTarget.IsUnrestricted()){\r
-                               return Copy();\r
-                       }\r
-                       else if (m_Unrestricted){\r
-                               return FIOPTarget.Copy();\r
-                       }\r
-                       else{\r
-                               FileIOPermission retVal = new FileIOPermission(PermissionState.None);\r
-                               retVal.AllFiles = m_AllFilesAccess & FIOPTarget.AllFiles;\r
-                               retVal.AllLocalFiles = m_AllLocalFilesAccess & FIOPTarget.AllLocalFiles;\r
-\r
-                               string[] paths;\r
-                               paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Append);\r
-                               if (null != paths) {\r
-                                       foreach (string path in paths){\r
-                                               if (m_PathList.ContainsKey(path) \r
-                                                       && ((FileIOPermissionAccess)m_PathList[path] & FileIOPermissionAccess.Append) != 0){\r
-                                                       retVal.AddPathList(FileIOPermissionAccess.Append, path);\r
-                                               }\r
-                                       }\r
-                               }\r
-\r
-                               paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Read);\r
-                               if (null != paths) {\r
-                                       foreach (string path in paths){\r
-                                               if (m_PathList.ContainsKey(path) \r
-                                                       && ((FileIOPermissionAccess)m_PathList[path] & FileIOPermissionAccess.Read) != 0){\r
-                                                       retVal.AddPathList(FileIOPermissionAccess.Read, path);\r
-                                               }\r
-                                       }\r
-                               }\r
-\r
-                               paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Write);\r
-                               if (null != paths) {\r
-                                       foreach (string path in paths){\r
-                                               if (m_PathList.ContainsKey(path) \r
-                                                       && ((FileIOPermissionAccess)m_PathList[path] & FileIOPermissionAccess.Write) != 0){\r
-                                                       retVal.AddPathList(FileIOPermissionAccess.Write, path);\r
-                                               }\r
-                                       }\r
-                               }\r
-\r
-                               return retVal;\r
-                       }\r
-               }\r
-\r
-\r
-               public override bool IsSubsetOf(IPermission target){\r
-                       // X.IsSubsetOf(Y) is true if permission Y includes everything allowed by X.\r
-                       if (target != null && target.GetType() != typeof(FileIOPermission)){\r
-                               throw new ArgumentException();\r
-                       }\r
-                       FileIOPermission FIOPTarget = (FileIOPermission)target;\r
-                       if (FIOPTarget.IsUnrestricted()){\r
-                               return true;\r
-                       }\r
-                       else if (m_Unrestricted){\r
-                               return false;\r
-                       }\r
-                       else if ((m_AllFilesAccess & FIOPTarget.AllFiles) != m_AllFilesAccess) {\r
-                               return false;\r
-                       }\r
-                       else if ((m_AllLocalFilesAccess & FIOPTarget.AllLocalFiles) != m_AllLocalFilesAccess) {\r
-                               return false;\r
-                       }\r
-                       else{\r
-                               string[] pathsNeeded;\r
-                               string[] pathsInTarget;\r
-\r
-                               pathsNeeded = GetPathList(FileIOPermissionAccess.Append);\r
-                               if (null != pathsNeeded) {\r
-                                       pathsInTarget = FIOPTarget.GetPathList(FileIOPermissionAccess.Append);\r
-                                       foreach (string path in pathsNeeded){\r
-                                               if (Array.IndexOf(pathsInTarget, path) <0) {\r
-                                                       return false;\r
-                                               }\r
-                                       }\r
-                               }\r
-\r
-                               pathsNeeded = GetPathList(FileIOPermissionAccess.Read);\r
-                               if (null != pathsNeeded) {\r
-                                       pathsInTarget = FIOPTarget.GetPathList(FileIOPermissionAccess.Read);\r
-                                       foreach (string path in pathsNeeded){\r
-                                               if (Array.IndexOf(pathsInTarget, path) <0) {\r
-                                                       return false;\r
-                                               }\r
-                                       }\r
-                               }\r
-\r
-                               pathsNeeded = GetPathList(FileIOPermissionAccess.Write);\r
-                               if (null != pathsNeeded) {\r
-                                       pathsInTarget = FIOPTarget.GetPathList(FileIOPermissionAccess.Write);\r
-                                       foreach (string path in pathsNeeded){\r
-                                               if (Array.IndexOf(pathsInTarget, path) <0) {\r
-                                                       return false;\r
-                                               }\r
-                                       }\r
-                               }\r
-\r
-                               return true;\r
-                       }\r
-               }\r
-\r
-               public bool IsUnrestricted(){\r
-                       return m_Unrestricted;\r
-               }\r
-\r
-               public void SetPathList(FileIOPermissionAccess access, string path){\r
-                       if ((FileIOPermissionAccess.AllAccess & access) != access){\r
-                               throw new ArgumentException("Illegal enum value: "+access.ToString()+".");\r
-                       }\r
-                       if (path.LastIndexOfAny(m_badCharacters) >= 0){\r
-                               throw new ArgumentException("Invalid characters in path: '{0}'", path);\r
-                       }\r
-\r
-                       m_PathList.Clear();\r
-                       AddPathList(access, path);\r
-               }\r
-               \r
-               public void SetPathList(FileIOPermissionAccess access, string[] pathList){\r
-                       if ((FileIOPermissionAccess.AllAccess & access) != access){\r
-                               throw new ArgumentException("Illegal enum value: "+access.ToString()+".");\r
-                       }\r
-                       foreach(string path in pathList){\r
-                               if (path.LastIndexOfAny(m_badCharacters) >= 0){\r
-                                       throw new ArgumentException("Invalid characters in path entry: '{0}'", path);\r
-                               }\r
-                       }\r
-\r
-                       m_PathList.Clear();\r
-                       AddPathList(access, pathList);\r
-               }\r
-\r
-               public override SecurityElement ToXml(){\r
-                       //Encode the the current permission to XML using the \r
-                       //security element class.\r
-                       SecurityElement element = new SecurityElement("IPermission");\r
-                       Type type = this.GetType();\r
-                       StringBuilder AsmName = new StringBuilder(type.Assembly.ToString());\r
-                       AsmName.Replace('\"', '\'');\r
-                       element.AddAttribute("class", type.FullName + ", " + AsmName);\r
-                       element.AddAttribute("version", "1");\r
-                       if(m_Unrestricted){\r
-                               element.AddAttribute("Unrestricted", "true");\r
-                       }\r
-                       else {\r
-                               string[] paths;\r
-                               paths = GetPathList(FileIOPermissionAccess.Append);\r
-                               if (null != paths && paths.Length >0){\r
-                                       element.AddAttribute("Append", String.Join(";",paths));\r
-                               }\r
-                               paths = GetPathList(FileIOPermissionAccess.Read);\r
-                               if (null != paths && paths.Length >0){\r
-                                       element.AddAttribute("Read", String.Join(";",paths));\r
-                               }\r
-                               paths = GetPathList(FileIOPermissionAccess.Write);\r
-                               if (null != paths && paths.Length >0){\r
-                                       element.AddAttribute("Write", String.Join(";",paths));\r
-                               }\r
-                       }\r
-                       return element;\r
-               }\r
-\r
-               public override IPermission Union(IPermission other){\r
-                       if (null == other){\r
-                               return null;\r
-                       }\r
-                       else {\r
-                               if (other.GetType() != typeof(FileIOPermission)){\r
-                                       throw new ArgumentException();\r
-                               }\r
-                       }\r
-                       FileIOPermission FIOPTarget = (FileIOPermission)other;\r
-                       if (FIOPTarget.IsUnrestricted() || m_Unrestricted){\r
-                               return new FileIOPermission(PermissionState.Unrestricted);\r
-                       }\r
-                       else{\r
-                               FileIOPermission retVal = (FileIOPermission)Copy();\r
-                               retVal.AllFiles |= FIOPTarget.AllFiles;\r
-                               retVal.AllLocalFiles |= FIOPTarget.AllLocalFiles;\r
-                               string[] paths;\r
-                               paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Append);\r
-                               if (null != paths){\r
-                                               retVal.AddPathList(FileIOPermissionAccess.Append, paths);\r
-                               }\r
-                               paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Read);\r
-                               if (null != paths){\r
-                                       retVal.AddPathList(FileIOPermissionAccess.Read, paths);\r
-                               }\r
-                               paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Write);\r
-                               if (null != paths){\r
-                                       retVal.AddPathList(FileIOPermissionAccess.Write, paths);\r
-                               }\r
-                               return retVal;\r
-                       }\r
-               }\r
-\r
-               // IBuiltInPermission\r
-               int IBuiltInPermission.GetTokenIndex ()\r
-               {\r
-                       return 2;\r
-               }\r
-       }\r
-}\r
+                       CreateLists ();
+                       // access and path will be validated in AddPathList
+                       AddPathList (access, pathList);
+               }
+
+               internal void CreateLists ()
+               {
+                       readList = new ArrayList ();
+                       writeList = new ArrayList ();
+                       appendList = new ArrayList ();
+                       pathList = new ArrayList ();
+               }
+
+               [MonoTODO ("(2.0) Access Control isn't implemented")]
+               public FileIOPermission (FileIOPermissionAccess access, AccessControlActions control, string path)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               [MonoTODO ("(2.0) Access Control isn't implemented")]
+               public FileIOPermission (FileIOPermissionAccess access, AccessControlActions control, string[] pathList)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               internal FileIOPermission (FileIOPermissionAccess access, string[] pathList, bool checkForDuplicates, bool needFullPath)
+               {
+               }
+
+               public FileIOPermissionAccess AllFiles {
+                       get { return m_AllFilesAccess; } 
+                       set {
+                               // if we are already set to unrestricted, don't change this property
+                               if (!m_Unrestricted){
+                                       m_AllFilesAccess = value;
+                               }
+                       }
+               }
+
+               public FileIOPermissionAccess AllLocalFiles {
+                       get { return m_AllLocalFilesAccess; } 
+                       set {
+                               // if we are already set to unrestricted, don't change this property
+                               if (!m_Unrestricted){
+                                       m_AllLocalFilesAccess = value;
+                               }
+                       }
+               }
+
+               public void AddPathList (FileIOPermissionAccess access, string path)
+               {
+                        if ((FileIOPermissionAccess.AllAccess & access) != access)
+                               ThrowInvalidFlag (access, true);
+                       ThrowIfInvalidPath (path);
+                       AddPathInternal (access, path);
+               }
+
+               public void AddPathList (FileIOPermissionAccess access, string[] pathList)
+               {
+                        if ((FileIOPermissionAccess.AllAccess & access) != access)
+                               ThrowInvalidFlag (access, true);
+                       ThrowIfInvalidPath (pathList);
+                       foreach (string path in pathList) {
+                               AddPathInternal (access, path);
+                       }
+               }
+
+               // internal to avoid duplicate checks
+               internal void AddPathInternal (FileIOPermissionAccess access, string path)
+               {
+                       // call InsecureGetFullPath (and not GetFullPath) to avoid recursion
+                       path = Path.InsecureGetFullPath (path);
+
+                       if ((access & FileIOPermissionAccess.Read) == FileIOPermissionAccess.Read)
+                               readList.Add (path);
+                       if ((access & FileIOPermissionAccess.Write) == FileIOPermissionAccess.Write)
+                               writeList.Add (path);
+                       if ((access & FileIOPermissionAccess.Append) == FileIOPermissionAccess.Append)
+                               appendList.Add (path);
+                       if ((access & FileIOPermissionAccess.PathDiscovery) == FileIOPermissionAccess.PathDiscovery)
+                               pathList.Add (path);
+               }
+
+               public override IPermission Copy ()
+               {
+                       if (m_Unrestricted)
+                               return new FileIOPermission (PermissionState.Unrestricted);
+
+                       FileIOPermission copy = new FileIOPermission (PermissionState.None);
+                       copy.readList = (ArrayList) readList.Clone ();
+                       copy.writeList = (ArrayList) writeList.Clone ();
+                       copy.appendList = (ArrayList) appendList.Clone ();
+                       copy.pathList = (ArrayList) pathList.Clone ();
+                       copy.m_AllFilesAccess = m_AllFilesAccess;
+                       copy.m_AllLocalFilesAccess = m_AllLocalFilesAccess;
+                       return copy;
+               }
+
+               public override void FromXml (SecurityElement esd)
+               {
+                       // General validation in CodeAccessPermission
+                       CheckSecurityElement (esd, "esd", version, version);
+                       // Note: we do not (yet) care about the return value 
+                       // as we only accept version 1 (min/max values)
+
+                       if (IsUnrestricted (esd)) {
+                               m_Unrestricted = true;
+                       }
+                       else{
+                               m_Unrestricted = false;
+                               string fileList = esd.Attribute ("Read");
+                               string[] files;
+                               if (fileList != null){
+                                       files = fileList.Split (';');
+                                       AddPathList (FileIOPermissionAccess.Read, files);
+                               }
+                               fileList = esd.Attribute ("Write");
+                               if (fileList != null){
+                                       files = fileList.Split (';');
+                                       AddPathList (FileIOPermissionAccess.Write, files);
+                               }
+                               fileList = esd.Attribute ("Append");
+                               if (fileList != null){
+                                       files = fileList.Split (';');
+                                       AddPathList (FileIOPermissionAccess.Append, files);
+                               }
+                               fileList = esd.Attribute ("PathDiscovery");
+                               if (fileList != null){
+                                       files = fileList.Split (';');
+                                       AddPathList (FileIOPermissionAccess.PathDiscovery, files);
+                               }
+                       }
+               }
+
+               public string[] GetPathList (FileIOPermissionAccess access)
+               {
+                        if ((FileIOPermissionAccess.AllAccess & access) != access)
+                               ThrowInvalidFlag (access, true);
+
+                       ArrayList result = new ArrayList ();
+                       switch (access) {
+                               case FileIOPermissionAccess.NoAccess:
+                                       break;
+                               case FileIOPermissionAccess.Read:
+                                       result.AddRange (readList);
+                                       break;
+                               case FileIOPermissionAccess.Write:
+                                       result.AddRange (writeList);
+                                       break;
+                               case FileIOPermissionAccess.Append:
+                                       result.AddRange (appendList);
+                                       break;
+                               case FileIOPermissionAccess.PathDiscovery:
+                                       result.AddRange (pathList);
+                                       break;
+                               default:
+                                       ThrowInvalidFlag (access, false);
+                                       break;
+                       }
+                       return (result.Count > 0) ? (string[]) result.ToArray (typeof (string)) : null;
+               }
+
+               public override IPermission Intersect (IPermission target)
+               {
+                       FileIOPermission fiop = Cast (target);
+                       if (fiop == null)
+                               return null;
+
+                       if (IsUnrestricted ())
+                               return fiop.Copy ();
+                       if (fiop.IsUnrestricted ())
+                               return Copy ();
+
+                       FileIOPermission result = new FileIOPermission (PermissionState.None);
+                       result.AllFiles = m_AllFilesAccess & fiop.AllFiles;
+                       result.AllLocalFiles = m_AllLocalFilesAccess & fiop.AllLocalFiles;
+
+                       IntersectKeys (readList, fiop.readList, result.readList);
+                       IntersectKeys (writeList, fiop.writeList, result.writeList);
+                       IntersectKeys (appendList, fiop.appendList, result.appendList);
+                       IntersectKeys (pathList, fiop.pathList, result.pathList);
+
+                       return (result.IsEmpty () ? null : result);
+               }
+
+               public override bool IsSubsetOf (IPermission target)
+               {
+                       FileIOPermission fiop = Cast (target);
+                       if (fiop == null) 
+                               return false;
+                       if (fiop.IsEmpty ())
+                               return IsEmpty ();
+
+                       if (IsUnrestricted ())
+                               return fiop.IsUnrestricted ();
+                       else if (fiop.IsUnrestricted ())
+                               return true;
+
+                       if ((m_AllFilesAccess & fiop.AllFiles) != m_AllFilesAccess)
+                               return false;
+                       if ((m_AllLocalFilesAccess & fiop.AllLocalFiles) != m_AllLocalFilesAccess)
+                               return false;
+
+                       if (!KeyIsSubsetOf (appendList, fiop.appendList))
+                               return false;
+                       if (!KeyIsSubsetOf (readList, fiop.readList))
+                               return false;
+                       if (!KeyIsSubsetOf (writeList, fiop.writeList))
+                               return false;
+                       if (!KeyIsSubsetOf (pathList, fiop.pathList))
+                               return false;
+
+                       return true;
+               }
+
+               public bool IsUnrestricted ()
+               {
+                       return m_Unrestricted;
+               }
+
+               public void SetPathList (FileIOPermissionAccess access, string path)
+               {
+                        if ((FileIOPermissionAccess.AllAccess & access) != access)
+                               ThrowInvalidFlag (access, true);
+                       ThrowIfInvalidPath (path);
+                       // note: throw before clearing the actual list
+                       Clear (access);
+                       AddPathInternal (access, path);
+               }
+               
+               public void SetPathList (FileIOPermissionAccess access, string[] pathList)
+               {
+                        if ((FileIOPermissionAccess.AllAccess & access) != access)
+                               ThrowInvalidFlag (access, true);
+                       ThrowIfInvalidPath (pathList);
+                       // note: throw before clearing the actual list
+                       Clear (access);
+                       foreach (string path in pathList)
+                               AddPathInternal (access, path);
+               }
+
+               public override SecurityElement ToXml ()
+               {
+                       SecurityElement se = Element (1);
+                       if (m_Unrestricted) {
+                               se.AddAttribute ("Unrestricted", "true");
+                       }
+                       else {
+                               string[] paths = GetPathList (FileIOPermissionAccess.Append);
+                               if (null != paths && paths.Length > 0) {
+                                       se.AddAttribute ("Append", String.Join (";", paths));
+                               }
+                               paths = GetPathList (FileIOPermissionAccess.Read);
+                               if (null != paths && paths.Length > 0) {
+                                       se.AddAttribute ("Read", String.Join (";", paths));
+                               }
+                               paths = GetPathList (FileIOPermissionAccess.Write);
+                               if (null != paths && paths.Length > 0) {
+                                       se.AddAttribute ("Write", String.Join  (";", paths));
+                               }
+                               paths = GetPathList (FileIOPermissionAccess.PathDiscovery);
+                               if (null != paths && paths.Length > 0) {
+                                       se.AddAttribute ("PathDiscovery", String.Join  (";", paths));
+                               }
+                       }
+                       return se;
+               }
+
+               public override IPermission Union (IPermission other)
+               {
+                       FileIOPermission fiop = Cast (other);
+                       if (fiop == null)
+                               return Copy ();
+
+                       if (IsUnrestricted () || fiop.IsUnrestricted ())
+                               return new FileIOPermission (PermissionState.Unrestricted);
+
+                       if (IsEmpty () && fiop.IsEmpty ())
+                               return null;
+
+                       FileIOPermission result = (FileIOPermission) Copy ();
+                       result.AllFiles |= fiop.AllFiles;
+                       result.AllLocalFiles |= fiop.AllLocalFiles;
+
+                       string[] paths = fiop.GetPathList (FileIOPermissionAccess.Read);
+                       if (paths != null) 
+                               UnionKeys (result.readList, paths);
+
+                       paths = fiop.GetPathList (FileIOPermissionAccess.Write);
+                       if (paths != null)
+                               UnionKeys (result.writeList, paths);
+
+                       paths = fiop.GetPathList (FileIOPermissionAccess.Append);
+                       if (paths != null) 
+                               UnionKeys (result.appendList, paths);
+
+                       paths = fiop.GetPathList (FileIOPermissionAccess.PathDiscovery);
+                       if (paths != null) 
+                               UnionKeys (result.pathList, paths);
+                       
+                       return result;
+               }
+
+               [MonoTODO ("(2.0)")]
+               [ComVisible (false)]
+               public override bool Equals (object obj)
+               {
+                       return false;
+               }
+
+               [MonoTODO ("(2.0)")]
+               [ComVisible (false)]
+               public override int GetHashCode ()
+               {
+                       return base.GetHashCode ();
+               }
+
+               // IBuiltInPermission
+               int IBuiltInPermission.GetTokenIndex ()
+               {
+                       return (int) BuiltInToken.FileIO;
+               }
+
+               // helpers
+
+               private bool IsEmpty ()
+               {
+                       return ((!m_Unrestricted) && (appendList.Count == 0) && (readList.Count == 0)
+                               && (writeList.Count == 0) && (pathList.Count == 0));
+               }
+
+               private static FileIOPermission Cast (IPermission target)
+               {
+                       if (target == null)
+                               return null;
+
+                       FileIOPermission fiop = (target as FileIOPermission);
+                       if (fiop == null) {
+                               ThrowInvalidPermission (target, typeof (FileIOPermission));
+                       }
+
+                       return fiop;
+               }
+
+               internal static void ThrowInvalidFlag (FileIOPermissionAccess access, bool context) 
+               {
+                       string msg = null;
+                       if (context)
+                               msg = Locale.GetText ("Unknown flag '{0}'.");
+                       else
+                               msg = Locale.GetText ("Invalid flag '{0}' in this context.");
+                       throw new ArgumentException (String.Format (msg, access), "access");
+               }
+
+               internal static void ThrowIfInvalidPath (string path)
+               {
+                       string dir = Path.GetDirectoryName (path);
+                       if ((dir != null) && (dir.LastIndexOfAny (BadPathNameCharacters) >= 0)) {
+                               string msg = String.Format (Locale.GetText ("Invalid path characters in path: '{0}'"), path);
+                               throw new ArgumentException (msg, "path");
+                       }
+
+                       string fname = Path.GetFileName (path);
+                       if ((fname != null) && (fname.LastIndexOfAny (BadFileNameCharacters) >= 0)) {
+                               string msg = String.Format (Locale.GetText ("Invalid filename characters in path: '{0}'"), path);
+                               throw new ArgumentException (msg, "path");
+                       }
+                       // LAMESPEC: docs don't say it must be a rooted path, but the MS implementation enforces it, so we will too.
+                       if (!Path.IsPathRooted (path)) {
+                               string msg = Locale.GetText ("Absolute path information is required.");
+                               throw new ArgumentException (msg, "path");
+                       }
+               }
+
+               internal static void ThrowIfInvalidPath (string[] paths)
+               {
+                       foreach (string path in paths)
+                               ThrowIfInvalidPath (path);
+               }
+
+               // we known that access is valid at this point
+               internal void Clear (FileIOPermissionAccess access)
+               {
+                       if ((access & FileIOPermissionAccess.Read) == FileIOPermissionAccess.Read)
+                               readList.Clear ();
+                       if ((access & FileIOPermissionAccess.Write) == FileIOPermissionAccess.Write)
+                               writeList.Clear ();
+                       if ((access & FileIOPermissionAccess.Append) == FileIOPermissionAccess.Append)
+                               appendList.Clear ();
+                       if ((access & FileIOPermissionAccess.PathDiscovery) == FileIOPermissionAccess.PathDiscovery)
+                               pathList.Clear ();
+               }
+
+               // note: all path in IList are already "full paths"
+               internal static bool KeyIsSubsetOf (IList local, IList target)
+               {
+                       bool result = false;
+                       foreach (string l in local) {
+                               foreach (string t in target) {
+                                       if (Path.IsPathSubsetOf (t, l)) {
+                                               result = true;
+                                               break;
+                                       }
+                               }
+                               if (!result)
+                                       return false;
+                       }
+                       return true;
+               }
+
+               internal static void UnionKeys (IList list, string[] paths)
+               {
+                       foreach (string path in paths) {
+                               int len = list.Count;
+                               if (len == 0) {
+                                       list.Add (path);
+                               }
+                               else {
+                                       int i;
+                                       for (i=0; i < len; i++) {
+                                               string s = (string) list [i];
+                                               if (Path.IsPathSubsetOf (path, s)) {
+                                                       // replace (with reduced version)
+                                                       list [i] = path;
+                                                       break;
+                                               }
+                                               else if (Path.IsPathSubsetOf (s, path)) {
+                                                       // no need to add
+                                                       break;
+                                               }
+                                       }
+                                       if (i == len) {
+                                               list.Add (path);
+                                       }
+                               }
+                       }
+               }
+
+               internal static void IntersectKeys (IList local, IList target, IList result)
+               {
+                       foreach (string l in local) {
+                               foreach (string t in target) {
+                                       if (t.Length > l.Length) {
+                                               if (Path.IsPathSubsetOf (l ,t))
+                                                       result.Add (t);
+                                       }
+                                       else {
+                                               if (Path.IsPathSubsetOf (t, l))
+                                                       result.Add (l);
+                                       }
+                               }
+                       }
+               }
+       }
+}