2 // System.Security.Permissions.FileIOPermission.cs
5 // Nick Drochak, ndrochak@gol.com
6 // Sebastien Pouliot <sebastien@ximian.com>
8 // Copyright (C) 2001 Nick Drochak, All Rights Reserved
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
35 using System.Runtime.InteropServices;
36 using System.Security.AccessControl;
38 namespace System.Security.Permissions {
42 public sealed class FileIOPermission
43 : CodeAccessPermission, IBuiltInPermission, IUnrestrictedPermission {
45 private const int version = 1;
47 private static char[] BadPathNameCharacters;
48 private static char[] BadFileNameCharacters;
50 static FileIOPermission ()
52 // we keep a local (static) copies to avoid calls/allocations
53 BadPathNameCharacters = Path.GetInvalidPathChars ();
54 BadFileNameCharacters = Path.GetInvalidFileNameChars ();
57 private bool m_Unrestricted = false;
58 private FileIOPermissionAccess m_AllFilesAccess = FileIOPermissionAccess.NoAccess;
59 private FileIOPermissionAccess m_AllLocalFilesAccess = FileIOPermissionAccess.NoAccess;
60 private ArrayList readList;
61 private ArrayList writeList;
62 private ArrayList appendList;
63 private ArrayList pathList;
65 public FileIOPermission (PermissionState state)
67 if (CheckPermissionState (state, true) == PermissionState.Unrestricted) {
68 m_Unrestricted = true;
69 m_AllFilesAccess = FileIOPermissionAccess.AllAccess;
70 m_AllLocalFilesAccess = FileIOPermissionAccess.AllAccess;
75 public FileIOPermission (FileIOPermissionAccess access, string path)
78 throw new ArgumentNullException ("path");
81 // access and path will be validated in AddPathList
82 AddPathList (access, path);
85 public FileIOPermission (FileIOPermissionAccess access, string[] pathList)
88 throw new ArgumentNullException ("pathList");
91 // access and path will be validated in AddPathList
92 AddPathList (access, pathList);
95 internal void CreateLists ()
97 readList = new ArrayList ();
98 writeList = new ArrayList ();
99 appendList = new ArrayList ();
100 pathList = new ArrayList ();
103 [MonoTODO ("(2.0) Access Control isn't implemented")]
104 public FileIOPermission (FileIOPermissionAccess access, AccessControlActions control, string path)
106 throw new NotImplementedException ();
109 [MonoTODO ("(2.0) Access Control isn't implemented")]
110 public FileIOPermission (FileIOPermissionAccess access, AccessControlActions control, string[] pathList)
112 throw new NotImplementedException ();
115 public FileIOPermissionAccess AllFiles {
116 get { return m_AllFilesAccess; }
118 // if we are already set to unrestricted, don't change this property
119 if (!m_Unrestricted){
120 m_AllFilesAccess = value;
125 public FileIOPermissionAccess AllLocalFiles {
126 get { return m_AllLocalFilesAccess; }
128 // if we are already set to unrestricted, don't change this property
129 if (!m_Unrestricted){
130 m_AllLocalFilesAccess = value;
135 public void AddPathList (FileIOPermissionAccess access, string path)
137 if ((FileIOPermissionAccess.AllAccess & access) != access)
138 ThrowInvalidFlag (access, true);
139 ThrowIfInvalidPath (path);
140 AddPathInternal (access, path);
143 public void AddPathList (FileIOPermissionAccess access, string[] pathList)
145 if ((FileIOPermissionAccess.AllAccess & access) != access)
146 ThrowInvalidFlag (access, true);
147 ThrowIfInvalidPath (pathList);
148 foreach (string path in pathList) {
149 AddPathInternal (access, path);
153 // internal to avoid duplicate checks
154 internal void AddPathInternal (FileIOPermissionAccess access, string path)
156 // call InsecureGetFullPath (and not GetFullPath) to avoid recursion
157 path = Path.InsecureGetFullPath (path);
159 if ((access & FileIOPermissionAccess.Read) == FileIOPermissionAccess.Read)
161 if ((access & FileIOPermissionAccess.Write) == FileIOPermissionAccess.Write)
162 writeList.Add (path);
163 if ((access & FileIOPermissionAccess.Append) == FileIOPermissionAccess.Append)
164 appendList.Add (path);
165 if ((access & FileIOPermissionAccess.PathDiscovery) == FileIOPermissionAccess.PathDiscovery)
169 public override IPermission Copy ()
172 return new FileIOPermission (PermissionState.Unrestricted);
174 FileIOPermission copy = new FileIOPermission (PermissionState.None);
175 copy.readList = (ArrayList) readList.Clone ();
176 copy.writeList = (ArrayList) writeList.Clone ();
177 copy.appendList = (ArrayList) appendList.Clone ();
178 copy.pathList = (ArrayList) pathList.Clone ();
179 copy.m_AllFilesAccess = m_AllFilesAccess;
180 copy.m_AllLocalFilesAccess = m_AllLocalFilesAccess;
184 public override void FromXml (SecurityElement esd)
186 // General validation in CodeAccessPermission
187 CheckSecurityElement (esd, "esd", version, version);
188 // Note: we do not (yet) care about the return value
189 // as we only accept version 1 (min/max values)
191 if (IsUnrestricted (esd)) {
192 m_Unrestricted = true;
195 m_Unrestricted = false;
196 string fileList = esd.Attribute ("Read");
198 if (fileList != null){
199 files = fileList.Split (';');
200 AddPathList (FileIOPermissionAccess.Read, files);
202 fileList = esd.Attribute ("Write");
203 if (fileList != null){
204 files = fileList.Split (';');
205 AddPathList (FileIOPermissionAccess.Write, files);
207 fileList = esd.Attribute ("Append");
208 if (fileList != null){
209 files = fileList.Split (';');
210 AddPathList (FileIOPermissionAccess.Append, files);
212 fileList = esd.Attribute ("PathDiscovery");
213 if (fileList != null){
214 files = fileList.Split (';');
215 AddPathList (FileIOPermissionAccess.PathDiscovery, files);
220 public string[] GetPathList (FileIOPermissionAccess access)
222 if ((FileIOPermissionAccess.AllAccess & access) != access)
223 ThrowInvalidFlag (access, true);
225 ArrayList result = new ArrayList ();
227 case FileIOPermissionAccess.NoAccess:
229 case FileIOPermissionAccess.Read:
230 result.AddRange (readList);
232 case FileIOPermissionAccess.Write:
233 result.AddRange (writeList);
235 case FileIOPermissionAccess.Append:
236 result.AddRange (appendList);
238 case FileIOPermissionAccess.PathDiscovery:
239 result.AddRange (pathList);
242 ThrowInvalidFlag (access, false);
245 return (result.Count > 0) ? (string[]) result.ToArray (typeof (string)) : null;
248 public override IPermission Intersect (IPermission target)
250 FileIOPermission fiop = Cast (target);
254 if (IsUnrestricted ())
256 if (fiop.IsUnrestricted ())
259 FileIOPermission result = new FileIOPermission (PermissionState.None);
260 result.AllFiles = m_AllFilesAccess & fiop.AllFiles;
261 result.AllLocalFiles = m_AllLocalFilesAccess & fiop.AllLocalFiles;
263 IntersectKeys (readList, fiop.readList, result.readList);
264 IntersectKeys (writeList, fiop.writeList, result.writeList);
265 IntersectKeys (appendList, fiop.appendList, result.appendList);
266 IntersectKeys (pathList, fiop.pathList, result.pathList);
268 return (result.IsEmpty () ? null : result);
271 public override bool IsSubsetOf (IPermission target)
273 FileIOPermission fiop = Cast (target);
279 if (IsUnrestricted ())
280 return fiop.IsUnrestricted ();
281 else if (fiop.IsUnrestricted ())
284 if ((m_AllFilesAccess & fiop.AllFiles) != m_AllFilesAccess)
286 if ((m_AllLocalFilesAccess & fiop.AllLocalFiles) != m_AllLocalFilesAccess)
289 if (!KeyIsSubsetOf (appendList, fiop.appendList))
291 if (!KeyIsSubsetOf (readList, fiop.readList))
293 if (!KeyIsSubsetOf (writeList, fiop.writeList))
295 if (!KeyIsSubsetOf (pathList, fiop.pathList))
301 public bool IsUnrestricted ()
303 return m_Unrestricted;
306 public void SetPathList (FileIOPermissionAccess access, string path)
308 if ((FileIOPermissionAccess.AllAccess & access) != access)
309 ThrowInvalidFlag (access, true);
310 ThrowIfInvalidPath (path);
311 // note: throw before clearing the actual list
313 AddPathInternal (access, path);
316 public void SetPathList (FileIOPermissionAccess access, string[] pathList)
318 if ((FileIOPermissionAccess.AllAccess & access) != access)
319 ThrowInvalidFlag (access, true);
320 ThrowIfInvalidPath (pathList);
321 // note: throw before clearing the actual list
323 foreach (string path in pathList)
324 AddPathInternal (access, path);
327 public override SecurityElement ToXml ()
329 SecurityElement se = Element (1);
330 if (m_Unrestricted) {
331 se.AddAttribute ("Unrestricted", "true");
334 string[] paths = GetPathList (FileIOPermissionAccess.Append);
335 if (null != paths && paths.Length > 0) {
336 se.AddAttribute ("Append", String.Join (";", paths));
338 paths = GetPathList (FileIOPermissionAccess.Read);
339 if (null != paths && paths.Length > 0) {
340 se.AddAttribute ("Read", String.Join (";", paths));
342 paths = GetPathList (FileIOPermissionAccess.Write);
343 if (null != paths && paths.Length > 0) {
344 se.AddAttribute ("Write", String.Join (";", paths));
346 paths = GetPathList (FileIOPermissionAccess.PathDiscovery);
347 if (null != paths && paths.Length > 0) {
348 se.AddAttribute ("PathDiscovery", String.Join (";", paths));
354 public override IPermission Union (IPermission other)
356 FileIOPermission fiop = Cast (other);
360 if (IsUnrestricted () || fiop.IsUnrestricted ())
361 return new FileIOPermission (PermissionState.Unrestricted);
363 if (IsEmpty () && fiop.IsEmpty ())
366 FileIOPermission result = (FileIOPermission) Copy ();
367 result.AllFiles |= fiop.AllFiles;
368 result.AllLocalFiles |= fiop.AllLocalFiles;
370 string[] paths = fiop.GetPathList (FileIOPermissionAccess.Read);
372 UnionKeys (result.readList, paths);
374 paths = fiop.GetPathList (FileIOPermissionAccess.Write);
376 UnionKeys (result.writeList, paths);
378 paths = fiop.GetPathList (FileIOPermissionAccess.Append);
380 UnionKeys (result.appendList, paths);
382 paths = fiop.GetPathList (FileIOPermissionAccess.PathDiscovery);
384 UnionKeys (result.pathList, paths);
391 public override bool Equals (object obj)
398 public override int GetHashCode ()
400 return base.GetHashCode ();
403 // IBuiltInPermission
404 int IBuiltInPermission.GetTokenIndex ()
406 return (int) BuiltInToken.FileIO;
411 private bool IsEmpty ()
413 return ((!m_Unrestricted) && (appendList.Count == 0) && (readList.Count == 0)
414 && (writeList.Count == 0) && (pathList.Count == 0));
417 private static FileIOPermission Cast (IPermission target)
422 FileIOPermission fiop = (target as FileIOPermission);
424 ThrowInvalidPermission (target, typeof (FileIOPermission));
430 internal static void ThrowInvalidFlag (FileIOPermissionAccess access, bool context)
434 msg = Locale.GetText ("Unknown flag '{0}'.");
436 msg = Locale.GetText ("Invalid flag '{0}' in this context.");
437 throw new ArgumentException (String.Format (msg, access), "access");
440 internal static void ThrowIfInvalidPath (string path)
442 string dir = Path.GetDirectoryName (path);
443 if ((dir != null) && (dir.LastIndexOfAny (BadPathNameCharacters) >= 0)) {
444 string msg = String.Format (Locale.GetText ("Invalid path characters in path: '{0}'"), path);
445 throw new ArgumentException (msg, "path");
448 string fname = Path.GetFileName (path);
449 if ((fname != null) && (fname.LastIndexOfAny (BadFileNameCharacters) >= 0)) {
450 string msg = String.Format (Locale.GetText ("Invalid filename characters in path: '{0}'"), path);
451 throw new ArgumentException (msg, "path");
453 // LAMESPEC: docs don't say it must be a rooted path, but the MS implementation enforces it, so we will too.
454 if (!Path.IsPathRooted (path)) {
455 string msg = Locale.GetText ("Absolute path information is required.");
456 throw new ArgumentException (msg, "path");
460 internal static void ThrowIfInvalidPath (string[] paths)
462 foreach (string path in paths)
463 ThrowIfInvalidPath (path);
466 // we known that access is valid at this point
467 internal void Clear (FileIOPermissionAccess access)
469 if ((access & FileIOPermissionAccess.Read) == FileIOPermissionAccess.Read)
471 if ((access & FileIOPermissionAccess.Write) == FileIOPermissionAccess.Write)
473 if ((access & FileIOPermissionAccess.Append) == FileIOPermissionAccess.Append)
475 if ((access & FileIOPermissionAccess.PathDiscovery) == FileIOPermissionAccess.PathDiscovery)
479 // note: all path in IList are already "full paths"
480 internal static bool KeyIsSubsetOf (IList local, IList target)
483 foreach (string l in local) {
484 foreach (string t in target) {
485 if (Path.IsPathSubsetOf (t, l)) {
496 internal static void UnionKeys (IList list, string[] paths)
498 foreach (string path in paths) {
499 int len = list.Count;
505 for (i=0; i < len; i++) {
506 string s = (string) list [i];
507 if (Path.IsPathSubsetOf (path, s)) {
508 // replace (with reduced version)
512 else if (Path.IsPathSubsetOf (s, path)) {
524 internal static void IntersectKeys (IList local, IList target, IList result)
526 foreach (string l in local) {
527 foreach (string t in target) {
528 if (t.Length > l.Length) {
529 if (Path.IsPathSubsetOf (l ,t))
533 if (Path.IsPathSubsetOf (t, l))