2 // System.Security.Permissions.FileIOPermission.cs
\r
5 // Nick Drochak, ndrochak@gol.com
\r
6 // Sebastien Pouliot <sebastien@ximian.com>
8 // Copyright (C) 2001 Nick Drochak, All Rights Reserved
\r
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;
\r
36 using System.Runtime.InteropServices;
37 using System.Security.AccessControl;
40 namespace System.Security.Permissions {
\r
46 public sealed class FileIOPermission
\r
47 : CodeAccessPermission, IBuiltInPermission, IUnrestrictedPermission {
\r
49 private const int version = 1;
52 private static char[] BadPathNameCharacters;
53 private static char[] BadFileNameCharacters;
55 static FileIOPermission ()
57 // we keep a local (static) copies to avoid calls/allocations
58 BadPathNameCharacters = Path.GetInvalidPathChars ();
59 BadFileNameCharacters = Path.GetInvalidFileNameChars ();
62 private static char[] m_badCharacters;
64 static FileIOPermission ()
66 // note: deprecated in 2.0 as InvalidPathChars is an array (i.e. items can be
67 // modified). Anyway we keep our own copy, which should be called by the
68 // security manager before anyone has the chance to change it.
69 m_badCharacters = (char[]) Path.InvalidPathChars.Clone ();
73 private bool m_Unrestricted = false;
\r
74 private FileIOPermissionAccess m_AllFilesAccess = FileIOPermissionAccess.NoAccess;
\r
75 private FileIOPermissionAccess m_AllLocalFilesAccess = FileIOPermissionAccess.NoAccess;
\r
76 private ArrayList readList;
77 private ArrayList writeList;
78 private ArrayList appendList;
79 private ArrayList pathList;
81 public FileIOPermission (PermissionState state)
83 if (CheckPermissionState (state, true) == PermissionState.Unrestricted) {
84 m_Unrestricted = true;
\r
85 m_AllFilesAccess = FileIOPermissionAccess.AllAccess;
\r
86 m_AllLocalFilesAccess = FileIOPermissionAccess.AllAccess;
\r
91 public FileIOPermission (FileIOPermissionAccess access, string path)
94 throw new ArgumentNullException ("path");
97 // access and path will be validated in AddPathList
\r
98 AddPathList (access, path);
\r
101 public FileIOPermission (FileIOPermissionAccess access, string[] pathList)
103 if (pathList == null)
104 throw new ArgumentNullException ("pathList");
107 // access and path will be validated in AddPathList
\r
108 AddPathList (access, pathList);
\r
111 internal void CreateLists ()
113 readList = new ArrayList ();
114 writeList = new ArrayList ();
115 appendList = new ArrayList ();
116 pathList = new ArrayList ();
120 [MonoTODO ("(2.0) Access Control isn't implemented")]
121 public FileIOPermission (FileIOPermissionAccess access, AccessControlActions control, string path)
123 throw new NotImplementedException ();
126 [MonoTODO ("(2.0) Access Control isn't implemented")]
127 public FileIOPermission (FileIOPermissionAccess access, AccessControlActions control, string[] pathList)
129 throw new NotImplementedException ();
133 public FileIOPermissionAccess AllFiles {
\r
134 get { return m_AllFilesAccess; }
\r
136 // if we are already set to unrestricted, don't change this property
\r
137 if (!m_Unrestricted){
\r
138 m_AllFilesAccess = value;
\r
143 public FileIOPermissionAccess AllLocalFiles {
\r
144 get { return m_AllLocalFilesAccess; }
\r
146 // if we are already set to unrestricted, don't change this property
\r
147 if (!m_Unrestricted){
\r
148 m_AllLocalFilesAccess = value;
\r
153 public void AddPathList (FileIOPermissionAccess access, string path)
155 if ((FileIOPermissionAccess.AllAccess & access) != access)
156 ThrowInvalidFlag (access, true);
157 ThrowIfInvalidPath (path);
\r
158 AddPathInternal (access, path);
\r
161 public void AddPathList (FileIOPermissionAccess access, string[] pathList)
163 if ((FileIOPermissionAccess.AllAccess & access) != access)
164 ThrowInvalidFlag (access, true);
165 ThrowIfInvalidPath (pathList);
\r
166 foreach (string path in pathList) {
167 AddPathInternal (access, path);
\r
171 // internal to avoid duplicate checks
172 internal void AddPathInternal (FileIOPermissionAccess access, string path)
174 // call InsecureGetFullPath (and not GetFullPath) to avoid recursion
175 path = Path.InsecureGetFullPath (path);
177 if ((access & FileIOPermissionAccess.Read) == FileIOPermissionAccess.Read)
179 if ((access & FileIOPermissionAccess.Write) == FileIOPermissionAccess.Write)
180 writeList.Add (path);
181 if ((access & FileIOPermissionAccess.Append) == FileIOPermissionAccess.Append)
182 appendList.Add (path);
183 if ((access & FileIOPermissionAccess.PathDiscovery) == FileIOPermissionAccess.PathDiscovery)
187 public override IPermission Copy ()
189 if (m_Unrestricted)
\r
190 return new FileIOPermission (PermissionState.Unrestricted);
\r
192 FileIOPermission copy = new FileIOPermission (PermissionState.None);
193 copy.readList = (ArrayList) readList.Clone ();
194 copy.writeList = (ArrayList) writeList.Clone ();
195 copy.appendList = (ArrayList) appendList.Clone ();
196 copy.pathList = (ArrayList) pathList.Clone ();
197 copy.m_AllFilesAccess = m_AllFilesAccess;
198 copy.m_AllLocalFilesAccess = m_AllLocalFilesAccess;
202 public override void FromXml (SecurityElement esd)
204 // General validation in CodeAccessPermission
205 CheckSecurityElement (esd, "esd", version, version);
206 // Note: we do not (yet) care about the return value
207 // as we only accept version 1 (min/max values)
209 if (IsUnrestricted (esd)) {
\r
210 m_Unrestricted = true;
\r
213 m_Unrestricted = false;
\r
214 string fileList = esd.Attribute ("Read");
\r
216 if (fileList != null){
\r
217 files = fileList.Split (';');
\r
218 AddPathList (FileIOPermissionAccess.Read, files);
\r
220 fileList = esd.Attribute ("Write");
\r
221 if (fileList != null){
\r
222 files = fileList.Split (';');
\r
223 AddPathList (FileIOPermissionAccess.Write, files);
\r
225 fileList = esd.Attribute ("Append");
\r
226 if (fileList != null){
\r
227 files = fileList.Split (';');
\r
228 AddPathList (FileIOPermissionAccess.Append, files);
\r
230 fileList = esd.Attribute ("PathDiscovery");
\r
231 if (fileList != null){
\r
232 files = fileList.Split (';');
\r
233 AddPathList (FileIOPermissionAccess.PathDiscovery, files);
\r
238 public string[] GetPathList (FileIOPermissionAccess access)
240 if ((FileIOPermissionAccess.AllAccess & access) != access)
241 ThrowInvalidFlag (access, true);
243 ArrayList result = new ArrayList ();
245 case FileIOPermissionAccess.NoAccess:
247 case FileIOPermissionAccess.Read:
248 result.AddRange (readList);
250 case FileIOPermissionAccess.Write:
251 result.AddRange (writeList);
253 case FileIOPermissionAccess.Append:
254 result.AddRange (appendList);
256 case FileIOPermissionAccess.PathDiscovery:
257 result.AddRange (pathList);
260 ThrowInvalidFlag (access, false);
263 return (result.Count > 0) ? (string[]) result.ToArray (typeof (string)) : null;
\r
266 public override IPermission Intersect (IPermission target)
268 FileIOPermission fiop = Cast (target);
272 if (IsUnrestricted ())
274 if (fiop.IsUnrestricted ())
277 FileIOPermission result = new FileIOPermission (PermissionState.None);
278 result.AllFiles = m_AllFilesAccess & fiop.AllFiles;
279 result.AllLocalFiles = m_AllLocalFilesAccess & fiop.AllLocalFiles;
281 IntersectKeys (readList, fiop.readList, result.readList);
282 IntersectKeys (writeList, fiop.writeList, result.writeList);
283 IntersectKeys (appendList, fiop.appendList, result.appendList);
284 IntersectKeys (pathList, fiop.pathList, result.pathList);
286 return (result.IsEmpty () ? null : result);
289 public override bool IsSubsetOf (IPermission target)
291 FileIOPermission fiop = Cast (target);
297 if (IsUnrestricted ())
298 return fiop.IsUnrestricted ();
299 else if (fiop.IsUnrestricted ())
302 if ((m_AllFilesAccess & fiop.AllFiles) != m_AllFilesAccess)
304 if ((m_AllLocalFilesAccess & fiop.AllLocalFiles) != m_AllLocalFilesAccess)
307 if (!KeyIsSubsetOf (appendList, fiop.appendList))
309 if (!KeyIsSubsetOf (readList, fiop.readList))
311 if (!KeyIsSubsetOf (writeList, fiop.writeList))
313 if (!KeyIsSubsetOf (pathList, fiop.pathList))
319 public bool IsUnrestricted ()
321 return m_Unrestricted;
\r
324 public void SetPathList (FileIOPermissionAccess access, string path)
326 if ((FileIOPermissionAccess.AllAccess & access) != access)
327 ThrowInvalidFlag (access, true);
328 ThrowIfInvalidPath (path);
\r
329 // note: throw before clearing the actual list
331 AddPathInternal (access, path);
\r
334 public void SetPathList (FileIOPermissionAccess access, string[] pathList)
336 if ((FileIOPermissionAccess.AllAccess & access) != access)
337 ThrowInvalidFlag (access, true);
338 ThrowIfInvalidPath (pathList);
\r
339 // note: throw before clearing the actual list
341 foreach (string path in pathList)
\r
342 AddPathInternal (access, path);
\r
345 public override SecurityElement ToXml ()
347 SecurityElement se = Element (1);
348 if (m_Unrestricted) {
\r
349 se.AddAttribute ("Unrestricted", "true");
\r
352 string[] paths = GetPathList (FileIOPermissionAccess.Append);
\r
353 if (null != paths && paths.Length > 0) {
\r
354 se.AddAttribute ("Append", String.Join (";", paths));
\r
356 paths = GetPathList (FileIOPermissionAccess.Read);
\r
357 if (null != paths && paths.Length > 0) {
\r
358 se.AddAttribute ("Read", String.Join (";", paths));
\r
360 paths = GetPathList (FileIOPermissionAccess.Write);
\r
361 if (null != paths && paths.Length > 0) {
\r
362 se.AddAttribute ("Write", String.Join (";", paths));
\r
364 paths = GetPathList (FileIOPermissionAccess.PathDiscovery);
\r
365 if (null != paths && paths.Length > 0) {
\r
366 se.AddAttribute ("PathDiscovery", String.Join (";", paths));
\r
372 public override IPermission Union (IPermission other)
374 FileIOPermission fiop = Cast (other);
378 if (IsUnrestricted () || fiop.IsUnrestricted ())
379 return new FileIOPermission (PermissionState.Unrestricted);
381 if (IsEmpty () && fiop.IsEmpty ())
384 FileIOPermission result = (FileIOPermission) Copy ();
385 result.AllFiles |= fiop.AllFiles;
386 result.AllLocalFiles |= fiop.AllLocalFiles;
388 string[] paths = fiop.GetPathList (FileIOPermissionAccess.Read);
390 UnionKeys (result.readList, paths);
392 paths = fiop.GetPathList (FileIOPermissionAccess.Write);
394 UnionKeys (result.writeList, paths);
396 paths = fiop.GetPathList (FileIOPermissionAccess.Append);
398 UnionKeys (result.appendList, paths);
400 paths = fiop.GetPathList (FileIOPermissionAccess.PathDiscovery);
402 UnionKeys (result.pathList, paths);
410 public override bool Equals (object obj)
417 public override int GetHashCode ()
419 return base.GetHashCode ();
423 // IBuiltInPermission
\r
424 int IBuiltInPermission.GetTokenIndex ()
\r
426 return (int) BuiltInToken.FileIO;
431 private bool IsEmpty ()
433 return ((!m_Unrestricted) && (appendList.Count == 0) && (readList.Count == 0)
434 && (writeList.Count == 0) && (pathList.Count == 0));
437 private static FileIOPermission Cast (IPermission target)
442 FileIOPermission fiop = (target as FileIOPermission);
444 ThrowInvalidPermission (target, typeof (FileIOPermission));
450 internal static void ThrowInvalidFlag (FileIOPermissionAccess access, bool context)
454 msg = Locale.GetText ("Unknown flag '{0}'.");
456 msg = Locale.GetText ("Invalid flag '{0}' in this context.");
457 throw new ArgumentException (String.Format (msg, access), "access");
460 internal static void ThrowIfInvalidPath (string path)
463 string dir = Path.GetDirectoryName (path);
464 if ((dir != null) && (dir.LastIndexOfAny (BadPathNameCharacters) >= 0)) {
465 string msg = String.Format (Locale.GetText ("Invalid path characters in path: '{0}'"), path);
\r
466 throw new ArgumentException (msg, "path");
\r
469 string fname = Path.GetFileName (path);
470 if ((fname != null) && (fname.LastIndexOfAny (BadFileNameCharacters) >= 0)) {
471 string msg = String.Format (Locale.GetText ("Invalid filename characters in path: '{0}'"), path);
\r
472 throw new ArgumentException (msg, "path");
\r
475 if (path.LastIndexOfAny (m_badCharacters) >= 0) {
\r
476 string msg = String.Format (Locale.GetText ("Invalid characters in path: '{0}'"), path);
\r
477 throw new ArgumentException (msg, "path");
\r
480 // LAMESPEC: docs don't say it must be a rooted path, but the MS implementation enforces it, so we will too.
\r
481 if (!Path.IsPathRooted (path)) {
482 string msg = Locale.GetText ("Absolute path information is required.");
483 throw new ArgumentException (msg, "path");
\r
487 internal static void ThrowIfInvalidPath (string[] paths)
489 foreach (string path in paths)
490 ThrowIfInvalidPath (path);
493 // we known that access is valid at this point
494 internal void Clear (FileIOPermissionAccess access)
496 if ((access & FileIOPermissionAccess.Read) == FileIOPermissionAccess.Read)
498 if ((access & FileIOPermissionAccess.Write) == FileIOPermissionAccess.Write)
500 if ((access & FileIOPermissionAccess.Append) == FileIOPermissionAccess.Append)
502 if ((access & FileIOPermissionAccess.PathDiscovery) == FileIOPermissionAccess.PathDiscovery)
506 // note: all path in IList are already "full paths"
507 internal static bool KeyIsSubsetOf (IList local, IList target)
510 foreach (string l in local) {
511 foreach (string t in target) {
512 if (Path.IsPathSubsetOf (t, l)) {
523 internal static void UnionKeys (IList list, string[] paths)
525 foreach (string path in paths) {
526 int len = list.Count;
532 for (i=0; i < len; i++) {
533 string s = (string) list [i];
534 if (Path.IsPathSubsetOf (path, s)) {
535 // replace (with reduced version)
539 else if (Path.IsPathSubsetOf (s, path)) {
551 internal static void IntersectKeys (IList local, IList target, IList result)
553 foreach (string l in local) {
554 foreach (string t in target) {
555 if (t.Length > l.Length) {
556 if (Path.IsPathSubsetOf (l ,t))
560 if (Path.IsPathSubsetOf (t, l))