-//------------------------------------------------------------------------------\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);
+ }
+ }
+ }
+ }
+ }
+}