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 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.Security.AccessControl;
39 namespace System.Security.Permissions {
\r
42 public sealed class FileIOPermission
\r
43 : CodeAccessPermission, IBuiltInPermission, IUnrestrictedPermission {
\r
45 private const int version = 1;
46 private static char[] m_badCharacters = {'\"','<', '>', '|', '*', '?'};
\r
48 private bool m_Unrestricted = false;
\r
49 private FileIOPermissionAccess m_AllFilesAccess = FileIOPermissionAccess.NoAccess;
\r
50 private FileIOPermissionAccess m_AllLocalFilesAccess = FileIOPermissionAccess.NoAccess;
\r
51 private ArrayList readList;
52 private ArrayList writeList;
53 private ArrayList appendList;
54 private ArrayList pathList;
56 public FileIOPermission (PermissionState state)
58 if (CheckPermissionState (state, true) == PermissionState.Unrestricted) {
59 m_Unrestricted = true;
\r
60 m_AllFilesAccess = FileIOPermissionAccess.AllAccess;
\r
61 m_AllLocalFilesAccess = FileIOPermissionAccess.AllAccess;
\r
66 public FileIOPermission (FileIOPermissionAccess access, string path)
69 throw new ArgumentNullException ("path");
72 // access and path will be validated in AddPathList
\r
73 AddPathList (access, path);
\r
76 public FileIOPermission (FileIOPermissionAccess access, string[] pathList)
79 throw new ArgumentNullException ("pathList");
82 // access and path will be validated in AddPathList
\r
83 AddPathList (access, pathList);
\r
86 internal void CreateLists ()
88 readList = new ArrayList ();
89 writeList = new ArrayList ();
90 appendList = new ArrayList ();
91 pathList = new ArrayList ();
95 [MonoTODO ("Access Control isn't implemented")]
96 public FileIOPermission (FileIOPermissionAccess access, AccessControlActions control, string path)
98 throw new NotImplementedException ();
101 [MonoTODO ("Access Control isn't implemented")]
102 public FileIOPermission (FileIOPermissionAccess access, AccessControlActions control, string[] pathList)
104 throw new NotImplementedException ();
108 public FileIOPermissionAccess AllFiles {
\r
109 get { return m_AllFilesAccess; }
\r
111 // if we are already set to unrestricted, don't change this property
\r
112 if (!m_Unrestricted){
\r
113 m_AllFilesAccess = value;
\r
118 public FileIOPermissionAccess AllLocalFiles {
\r
119 get { return m_AllLocalFilesAccess; }
\r
121 // if we are already set to unrestricted, don't change this property
\r
122 if (!m_Unrestricted){
\r
123 m_AllLocalFilesAccess = value;
\r
128 public void AddPathList (FileIOPermissionAccess access, string path)
130 if ((FileIOPermissionAccess.AllAccess & access) != access)
131 ThrowInvalidFlag (access, true);
132 ThrowIfInvalidPath (path);
\r
133 AddPathInternal (access, path);
\r
136 public void AddPathList (FileIOPermissionAccess access, string[] pathList)
138 if ((FileIOPermissionAccess.AllAccess & access) != access)
139 ThrowInvalidFlag (access, true);
140 ThrowIfInvalidPath (pathList);
\r
141 foreach (string path in pathList) {
142 AddPathInternal (access, path);
\r
146 // internal to avoid duplicate checks
147 internal void AddPathInternal (FileIOPermissionAccess access, string path)
149 path = Path.GetFullPath (path);
151 case FileIOPermissionAccess.AllAccess:
153 writeList.Add (path);
154 appendList.Add (path);
157 case FileIOPermissionAccess.NoAccess:
158 // ??? unit tests doesn't show removal using NoAccess ???
160 case FileIOPermissionAccess.Read:
163 case FileIOPermissionAccess.Write:
164 writeList.Add (path);
166 case FileIOPermissionAccess.Append:
167 appendList.Add (path);
169 case FileIOPermissionAccess.PathDiscovery:
173 ThrowInvalidFlag (access, true);
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 //LAMESPEC: docs says it returns (semicolon separated) list, but return
\r
244 //type is array. I think docs are wrong and it just returns an array
245 ArrayList result = new ArrayList ();
247 case FileIOPermissionAccess.NoAccess:
249 case FileIOPermissionAccess.Read:
250 result.AddRange (readList);
252 case FileIOPermissionAccess.Write:
253 result.AddRange (writeList);
255 case FileIOPermissionAccess.Append:
256 result.AddRange (appendList);
258 case FileIOPermissionAccess.PathDiscovery:
259 result.AddRange (pathList);
262 ThrowInvalidFlag (access, false);
265 return (result.Count > 0) ? (string[]) result.ToArray (typeof (string)) : null;
\r
268 public override IPermission Intersect (IPermission target)
270 FileIOPermission fiop = Cast (target);
274 if (IsUnrestricted ())
276 if (fiop.IsUnrestricted ())
279 FileIOPermission result = new FileIOPermission (PermissionState.None);
280 result.AllFiles = m_AllFilesAccess & fiop.AllFiles;
281 result.AllLocalFiles = m_AllLocalFilesAccess & fiop.AllLocalFiles;
283 IntersectKeys (readList, fiop.readList, result.readList);
284 IntersectKeys (writeList, fiop.writeList, result.writeList);
285 IntersectKeys (appendList, fiop.appendList, result.appendList);
286 IntersectKeys (pathList, fiop.pathList, result.pathList);
288 return (result.IsEmpty () ? null : result);
292 public override bool IsSubsetOf (IPermission target)
294 FileIOPermission fiop = Cast (target);
300 if (IsUnrestricted ())
301 return fiop.IsUnrestricted ();
302 else if (fiop.IsUnrestricted ())
305 if ((m_AllFilesAccess & fiop.AllFiles) != m_AllFilesAccess)
307 if ((m_AllLocalFilesAccess & fiop.AllLocalFiles) != m_AllLocalFilesAccess)
310 if (!KeyIsSubsetOf (appendList, fiop.appendList))
312 if (!KeyIsSubsetOf (readList, fiop.readList))
314 if (!KeyIsSubsetOf (writeList, fiop.writeList))
316 if (!KeyIsSubsetOf (pathList, fiop.pathList))
322 public bool IsUnrestricted ()
324 return m_Unrestricted;
\r
327 public void SetPathList (FileIOPermissionAccess access, string path)
329 if ((FileIOPermissionAccess.AllAccess & access) != access)
330 ThrowInvalidFlag (access, true);
331 ThrowIfInvalidPath (path);
\r
332 // note: throw before clearing the actual list
334 AddPathInternal (access, path);
\r
337 public void SetPathList (FileIOPermissionAccess access, string[] pathList)
339 if ((FileIOPermissionAccess.AllAccess & access) != access)
340 ThrowInvalidFlag (access, true);
341 ThrowIfInvalidPath (pathList);
\r
342 // note: throw before clearing the actual list
344 foreach (string path in pathList)
\r
345 AddPathInternal (access, path);
\r
348 public override SecurityElement ToXml ()
350 SecurityElement se = Element (1);
351 if (m_Unrestricted) {
\r
352 se.AddAttribute ("Unrestricted", "true");
\r
355 string[] paths = GetPathList (FileIOPermissionAccess.Append);
\r
356 if (null != paths && paths.Length > 0) {
\r
357 se.AddAttribute ("Append", String.Join (";", paths));
\r
359 paths = GetPathList (FileIOPermissionAccess.Read);
\r
360 if (null != paths && paths.Length > 0) {
\r
361 se.AddAttribute ("Read", String.Join (";", paths));
\r
363 paths = GetPathList (FileIOPermissionAccess.Write);
\r
364 if (null != paths && paths.Length > 0) {
\r
365 se.AddAttribute ("Write", String.Join (";", paths));
\r
367 paths = GetPathList (FileIOPermissionAccess.PathDiscovery);
\r
368 if (null != paths && paths.Length > 0) {
\r
369 se.AddAttribute ("PathDiscovery", String.Join (";", paths));
\r
375 public override IPermission Union (IPermission other)
377 FileIOPermission fiop = Cast (other);
381 if (IsUnrestricted () || fiop.IsUnrestricted ())
382 return new FileIOPermission (PermissionState.Unrestricted);
384 if (IsEmpty () && fiop.IsEmpty ())
387 FileIOPermission result = (FileIOPermission) Copy ();
388 result.AllFiles |= fiop.AllFiles;
389 result.AllLocalFiles |= fiop.AllLocalFiles;
391 string[] paths = fiop.GetPathList (FileIOPermissionAccess.Read);
393 UnionKeys (result.readList, paths);
395 paths = fiop.GetPathList (FileIOPermissionAccess.Write);
397 UnionKeys (result.writeList, paths);
399 paths = fiop.GetPathList (FileIOPermissionAccess.Append);
401 UnionKeys (result.appendList, paths);
403 paths = fiop.GetPathList (FileIOPermissionAccess.PathDiscovery);
405 UnionKeys (result.pathList, paths);
412 public override bool Equals (object obj)
418 public override int GetHashCode ()
420 return base.GetHashCode ();
424 // IBuiltInPermission
\r
425 int IBuiltInPermission.GetTokenIndex ()
\r
427 return (int) BuiltInToken.FileIO;
432 private bool IsEmpty ()
434 return ((!m_Unrestricted) && (appendList.Count == 0) && (readList.Count == 0)
435 && (writeList.Count == 0) && (pathList.Count == 0));
438 private FileIOPermission Cast (IPermission target)
443 FileIOPermission fiop = (target as FileIOPermission);
445 ThrowInvalidPermission (target, typeof (FileIOPermission));
451 internal void ThrowInvalidFlag (FileIOPermissionAccess access, bool context)
455 msg = Locale.GetText ("Unknown flag '{0}'.");
457 msg = Locale.GetText ("Invalid flag '{0}' in this context.");
458 throw new ArgumentException (String.Format (msg, access), "access");
461 internal void ThrowIfInvalidPath (string path)
463 if (path.LastIndexOfAny (m_badCharacters) >= 0) {
\r
464 string msg = String.Format (Locale.GetText ("Invalid characters in path: '{0}'"), path);
\r
465 throw new ArgumentException (msg, "path");
\r
467 // LAMESPEC: docs don't say it must be a rooted path, but the MS implementation enforces it, so we will too.
\r
468 if (!Path.IsPathRooted (path)) {
469 string msg = Locale.GetText ("Absolute path information is required.");
\r
470 throw new ArgumentException (msg, "path");
\r
474 internal void ThrowIfInvalidPath (string[] paths)
476 foreach (string path in paths)
477 ThrowIfInvalidPath (path);
480 // we known that access is valid at this point
481 internal void Clear (FileIOPermissionAccess access)
483 if ((access & FileIOPermissionAccess.Read) == FileIOPermissionAccess.Read)
485 if ((access & FileIOPermissionAccess.Write) == FileIOPermissionAccess.Write)
487 if ((access & FileIOPermissionAccess.Append) == FileIOPermissionAccess.Append)
489 if ((access & FileIOPermissionAccess.PathDiscovery) == FileIOPermissionAccess.PathDiscovery)
493 internal bool KeyIsSubsetOf (IList local, IList target)
496 foreach (string l in local) {
497 string c14nl = Path.GetFullPath (l);
498 foreach (string t in target) {
499 if (c14nl.StartsWith (Path.GetFullPath (t))) {
510 internal void UnionKeys (IList list, string[] paths)
512 foreach (string p in paths) {
514 string path = Path.GetFullPath (p);
515 int len = list.Count;
520 for (int i=0; i < len; i++) {
522 string s = Path.GetFullPath ((string) list [i]);
523 if (s.StartsWith (path)) {
524 // replace (with reduced version)
528 else if (path.StartsWith (s)) {
541 internal void IntersectKeys (IList local, IList target, IList result)
543 foreach (string l in local) {
544 foreach (string t in target) {
545 if (t.Length > l.Length) {
546 if (t.StartsWith (l))
550 if (l.StartsWith (t))