X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FSystem.Security.Permissions%2FFileIOPermission.cs;h=c08313b278fd1ee0bd9a4425621eb3014f573494;hb=9b4b6d621101fdf06e41b0f76b1ad50b0d1149f2;hp=8113954f2030a3c8d81d195623f6c4526bde8cf4;hpb=13d1764537ce5bbe5a06bf133fb2db1a4b5d2131;p=mono.git diff --git a/mcs/class/corlib/System.Security.Permissions/FileIOPermission.cs b/mcs/class/corlib/System.Security.Permissions/FileIOPermission.cs index 8113954f203..c08313b278f 100644 --- a/mcs/class/corlib/System.Security.Permissions/FileIOPermission.cs +++ b/mcs/class/corlib/System.Security.Permissions/FileIOPermission.cs @@ -1,16 +1,12 @@ -//------------------------------------------------------------------------------ -// -// System.Security.Permissions.FileIOPermission.cs -// -// Copyright (C) 2001 Nick Drochak, All Rights Reserved -// -// Author: Nick Drochak, ndrochak@gol.com -// Created: 2002-01-09 -// -//------------------------------------------------------------------------------ - +// +// System.Security.Permissions.FileIOPermission.cs // -// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// Authors: +// Nick Drochak, ndrochak@gol.com +// Sebastien Pouliot +// +// 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 @@ -31,417 +27,518 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // - -using System.Collections; -using System.IO; -using System.Text; - -namespace System.Security.Permissions { - - [Serializable] - public sealed class FileIOPermission - : CodeAccessPermission, IBuiltInPermission, IUnrestrictedPermission { - - private static char[] m_badCharacters = {'\"','<', '>', '|', '*', '?'}; - private bool m_Unrestricted = false; - private Hashtable m_PathList = new Hashtable(); - private FileIOPermissionAccess m_AllFilesAccess = FileIOPermissionAccess.NoAccess; - private FileIOPermissionAccess m_AllLocalFilesAccess = FileIOPermissionAccess.NoAccess; - - public FileIOPermission(PermissionState state) { - if (!Enum.IsDefined(typeof(PermissionState), state)){ - throw new ArgumentException("Invalid permission state.", "state"); - } - m_Unrestricted = (PermissionState.Unrestricted == state); - if (m_Unrestricted) { - m_AllFilesAccess = FileIOPermissionAccess.AllAccess; - m_AllLocalFilesAccess = FileIOPermissionAccess.AllAccess; - } - } - - 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"); - - if ((FileIOPermissionAccess.AllAccess & access) != access){ - throw new ArgumentException("Illegal enum value: "+access.ToString()+"."); - } - - if (path.LastIndexOfAny(m_badCharacters) >= 0){ - throw new ArgumentException("Illegal characters found in input. Security checks can not contain wild card characters.", "path"); - } - - AddPathList(access, path); - } - - public FileIOPermission(FileIOPermissionAccess access, string[] pathList) - { + + 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){ - throw new ArgumentException("Illegal enum value: "+access.ToString()+"."); - } - - AddPathList(access, pathList); - } - - 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){ - throw new ArgumentException("Illegal enum value: {0}.",access.ToString()); - } - - if (path.LastIndexOfAny(m_badCharacters) >= 0){ - throw new ArgumentException("Invalid characters in path: '{0}'", 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)) { - throw new ArgumentException("Absolute path information is required."); - } - - // don't add the same path twice, instead overwrite access entry for that path - if (m_PathList.ContainsKey(path)) { - FileIOPermissionAccess currentPermission = (FileIOPermissionAccess)m_PathList[path]; - currentPermission |= access; - m_PathList[path] = currentPermission; - } - else { - m_PathList.Add(path, access); - } - } - - public void AddPathList(FileIOPermissionAccess access, string[] pathList ){ - foreach(string path in pathList){ - AddPathList(access, path); - } - - } - - // private constructor used by Copy() method - private FileIOPermission(Hashtable pathList, FileIOPermissionAccess allFiles, - FileIOPermissionAccess allLocalFiles, bool unrestricted){ - m_PathList = pathList; - m_AllFilesAccess = allFiles; - m_AllLocalFilesAccess = allLocalFiles; - m_Unrestricted = unrestricted; - } - - public override IPermission Copy(){ - if (m_Unrestricted) { - return new FileIOPermission(PermissionState.Unrestricted); - } - else{ - FileIOPermission retVal = new FileIOPermission(m_PathList, m_AllFilesAccess, m_AllLocalFilesAccess, m_Unrestricted); - return retVal; - } - } - - /* XML Schema for FileIOPermission - - */ - public override void FromXml(SecurityElement esd){ - if (null == esd) { - throw new ArgumentNullException(); - } - if (esd.Tag != "IPermission" || (string)esd.Attributes["class"] != "FileIOPermission" - || (string)esd.Attributes["version"] != "1"){ - throw new ArgumentException("Not a valid permission element"); - } - m_PathList.Clear(); - if ("true" == (string)esd.Attributes["Unrestricted"]){ - m_Unrestricted = true; - } - else{ - m_Unrestricted = false; - string fileList; - fileList = (string)esd.Attributes["Read"]; - string[] files; - if (fileList != null){ - files = fileList.Split(';'); - AddPathList(FileIOPermissionAccess.Read, files); - } - fileList = (string)esd.Attributes["Write"]; - if (fileList != null){ - files = fileList.Split(';'); - AddPathList(FileIOPermissionAccess.Write, files); - } - fileList = (string)esd.Attributes["Append"]; - if (fileList != null){ - files = fileList.Split(';'); - AddPathList(FileIOPermissionAccess.Append, files); - } - } - } - - public string[] GetPathList(FileIOPermissionAccess access){ - //LAMESPEC: docs says it returns (semicolon separated) list, but return - //type is array. I think docs are wrong and it just returns an array - if ((FileIOPermissionAccess.AllAccess & access) != access){ - throw new ArgumentException("Illegal enum value: "+access.ToString()+"."); - } - - ArrayList matchingPaths = new ArrayList(); - System.Collections.IDictionaryEnumerator pathListIterator = m_PathList.GetEnumerator(); - while (pathListIterator.MoveNext()) { - if (((FileIOPermissionAccess)pathListIterator.Value & access) != 0) { - matchingPaths.Add((string)pathListIterator.Key); - } - } - if (matchingPaths.Count == 0) { - return null; - } - else { - return (string[])matchingPaths.ToArray(typeof(string)); - } - } - - public override IPermission Intersect(IPermission target){ - if (null == target){ - return null; - } - else { - if (target.GetType() != typeof(FileIOPermission)){ - throw new ArgumentException(); - } - } - FileIOPermission FIOPTarget = (FileIOPermission)target; - if (FIOPTarget.IsUnrestricted() && m_Unrestricted){ - return new FileIOPermission(PermissionState.Unrestricted); - } - else if (FIOPTarget.IsUnrestricted()){ - return Copy(); - } - else if (m_Unrestricted){ - return FIOPTarget.Copy(); - } - else{ - FileIOPermission retVal = new FileIOPermission(PermissionState.None); - retVal.AllFiles = m_AllFilesAccess & FIOPTarget.AllFiles; - retVal.AllLocalFiles = m_AllLocalFilesAccess & FIOPTarget.AllLocalFiles; - - string[] paths; - paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Append); - if (null != paths) { - foreach (string path in paths){ - if (m_PathList.ContainsKey(path) - && ((FileIOPermissionAccess)m_PathList[path] & FileIOPermissionAccess.Append) != 0){ - retVal.AddPathList(FileIOPermissionAccess.Append, path); - } - } - } - - paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Read); - if (null != paths) { - foreach (string path in paths){ - if (m_PathList.ContainsKey(path) - && ((FileIOPermissionAccess)m_PathList[path] & FileIOPermissionAccess.Read) != 0){ - retVal.AddPathList(FileIOPermissionAccess.Read, path); - } - } - } - - paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Write); - if (null != paths) { - foreach (string path in paths){ - if (m_PathList.ContainsKey(path) - && ((FileIOPermissionAccess)m_PathList[path] & FileIOPermissionAccess.Write) != 0){ - retVal.AddPathList(FileIOPermissionAccess.Write, path); - } - } - } - - return retVal; - } - } - - - public override bool IsSubsetOf(IPermission target){ - // X.IsSubsetOf(Y) is true if permission Y includes everything allowed by X. - if (target != null && target.GetType() != typeof(FileIOPermission)){ - throw new ArgumentException(); - } - FileIOPermission FIOPTarget = (FileIOPermission)target; - if (FIOPTarget.IsUnrestricted()){ - return true; - } - else if (m_Unrestricted){ - return false; - } - else if ((m_AllFilesAccess & FIOPTarget.AllFiles) != m_AllFilesAccess) { - return false; - } - else if ((m_AllLocalFilesAccess & FIOPTarget.AllLocalFiles) != m_AllLocalFilesAccess) { - return false; - } - else{ - string[] pathsNeeded; - string[] pathsInTarget; - - pathsNeeded = GetPathList(FileIOPermissionAccess.Append); - if (null != pathsNeeded) { - pathsInTarget = FIOPTarget.GetPathList(FileIOPermissionAccess.Append); - foreach (string path in pathsNeeded){ - if (Array.IndexOf(pathsInTarget, path) <0) { - return false; - } - } - } - - pathsNeeded = GetPathList(FileIOPermissionAccess.Read); - if (null != pathsNeeded) { - pathsInTarget = FIOPTarget.GetPathList(FileIOPermissionAccess.Read); - foreach (string path in pathsNeeded){ - if (Array.IndexOf(pathsInTarget, path) <0) { - return false; - } - } - } - - pathsNeeded = GetPathList(FileIOPermissionAccess.Write); - if (null != pathsNeeded) { - pathsInTarget = FIOPTarget.GetPathList(FileIOPermissionAccess.Write); - foreach (string path in pathsNeeded){ - if (Array.IndexOf(pathsInTarget, path) <0) { - return false; - } - } - } - - return true; - } - } - - public bool IsUnrestricted(){ - return m_Unrestricted; - } - - public void SetPathList(FileIOPermissionAccess access, string path){ - if ((FileIOPermissionAccess.AllAccess & access) != access){ - throw new ArgumentException("Illegal enum value: "+access.ToString()+"."); - } - if (path.LastIndexOfAny(m_badCharacters) >= 0){ - throw new ArgumentException("Invalid characters in path: '{0}'", path); - } - - m_PathList.Clear(); - AddPathList(access, path); - } - - public void SetPathList(FileIOPermissionAccess access, string[] pathList){ - if ((FileIOPermissionAccess.AllAccess & access) != access){ - throw new ArgumentException("Illegal enum value: "+access.ToString()+"."); - } - foreach(string path in pathList){ - if (path.LastIndexOfAny(m_badCharacters) >= 0){ - throw new ArgumentException("Invalid characters in path entry: '{0}'", path); - } - } - - m_PathList.Clear(); - AddPathList(access, pathList); - } - - public override SecurityElement ToXml(){ - //Encode the the current permission to XML using the - //security element class. - SecurityElement element = new SecurityElement("IPermission"); - Type type = this.GetType(); - StringBuilder AsmName = new StringBuilder(type.Assembly.ToString()); - AsmName.Replace('\"', '\''); - element.AddAttribute("class", type.FullName + ", " + AsmName); - element.AddAttribute("version", "1"); - if(m_Unrestricted){ - element.AddAttribute("Unrestricted", "true"); - } - else { - string[] paths; - paths = GetPathList(FileIOPermissionAccess.Append); - if (null != paths && paths.Length >0){ - element.AddAttribute("Append", String.Join(";",paths)); - } - paths = GetPathList(FileIOPermissionAccess.Read); - if (null != paths && paths.Length >0){ - element.AddAttribute("Read", String.Join(";",paths)); - } - paths = GetPathList(FileIOPermissionAccess.Write); - if (null != paths && paths.Length >0){ - element.AddAttribute("Write", String.Join(";",paths)); - } - } - return element; - } - - public override IPermission Union(IPermission other){ - if (null == other){ - return null; - } - else { - if (other.GetType() != typeof(FileIOPermission)){ - throw new ArgumentException(); - } - } - FileIOPermission FIOPTarget = (FileIOPermission)other; - if (FIOPTarget.IsUnrestricted() || m_Unrestricted){ - return new FileIOPermission(PermissionState.Unrestricted); - } - else{ - FileIOPermission retVal = (FileIOPermission)Copy(); - retVal.AllFiles |= FIOPTarget.AllFiles; - retVal.AllLocalFiles |= FIOPTarget.AllLocalFiles; - string[] paths; - paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Append); - if (null != paths){ - retVal.AddPathList(FileIOPermissionAccess.Append, paths); - } - paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Read); - if (null != paths){ - retVal.AddPathList(FileIOPermissionAccess.Read, paths); - } - paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Write); - if (null != paths){ - retVal.AddPathList(FileIOPermissionAccess.Write, paths); - } - return retVal; - } - } - - // IBuiltInPermission - int IBuiltInPermission.GetTokenIndex () - { - return 2; - } - } -} + 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); + } + } + } + } + } +}