**** Merged from MCS ****
[mono-project.git] / mcs / class / corlib / System.Security.Permissions / FileIOPermission.cs
blob15d09b1d3ae42bf639776e98b397f01ec175b4b2
1 //
2 // System.Security.Permissions.FileIOPermission.cs
3 //
4 // Authors:
5 // Nick Drochak, ndrochak@gol.com
6 // Sebastien Pouliot <sebastien@ximian.com>
7 //
8 // Copyright (C) 2001 Nick Drochak, All Rights Reserved
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:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
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;
32 using System.IO;
33 using System.Text;
35 #if NET_2_0
36 using System.Security.AccessControl;
37 #endif
39 namespace System.Security.Permissions {
41 [Serializable]
42 public sealed class FileIOPermission
43 : CodeAccessPermission, IBuiltInPermission, IUnrestrictedPermission {
45 private const int version = 1;
46 private static char[] m_badCharacters = {'\"','<', '>', '|', '*', '?'};
48 private bool m_Unrestricted = false;
49 private FileIOPermissionAccess m_AllFilesAccess = FileIOPermissionAccess.NoAccess;
50 private FileIOPermissionAccess m_AllLocalFilesAccess = FileIOPermissionAccess.NoAccess;
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;
60 m_AllFilesAccess = FileIOPermissionAccess.AllAccess;
61 m_AllLocalFilesAccess = FileIOPermissionAccess.AllAccess;
63 CreateLists ();
66 public FileIOPermission (FileIOPermissionAccess access, string path)
68 if (path == null)
69 throw new ArgumentNullException ("path");
71 CreateLists ();
72 // access and path will be validated in AddPathList
73 AddPathList (access, path);
76 public FileIOPermission (FileIOPermissionAccess access, string[] pathList)
78 if (pathList == null)
79 throw new ArgumentNullException ("pathList");
81 CreateLists ();
82 // access and path will be validated in AddPathList
83 AddPathList (access, pathList);
86 internal void CreateLists ()
88 readList = new ArrayList ();
89 writeList = new ArrayList ();
90 appendList = new ArrayList ();
91 pathList = new ArrayList ();
94 #if NET_2_0
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 ();
106 #endif
108 public FileIOPermissionAccess AllFiles {
109 get { return m_AllFilesAccess; }
110 set {
111 // if we are already set to unrestricted, don't change this property
112 if (!m_Unrestricted){
113 m_AllFilesAccess = value;
118 public FileIOPermissionAccess AllLocalFiles {
119 get { return m_AllLocalFilesAccess; }
120 set {
121 // if we are already set to unrestricted, don't change this property
122 if (!m_Unrestricted){
123 m_AllLocalFilesAccess = value;
128 public void AddPathList (FileIOPermissionAccess access, string path)
130 if ((FileIOPermissionAccess.AllAccess & access) != access)
131 ThrowInvalidFlag (access, true);
132 ThrowIfInvalidPath (path);
133 AddPathInternal (access, path);
136 public void AddPathList (FileIOPermissionAccess access, string[] pathList)
138 if ((FileIOPermissionAccess.AllAccess & access) != access)
139 ThrowInvalidFlag (access, true);
140 ThrowIfInvalidPath (pathList);
141 foreach (string path in pathList) {
142 AddPathInternal (access, path);
146 // internal to avoid duplicate checks
147 internal void AddPathInternal (FileIOPermissionAccess access, string path)
149 path = Path.GetFullPath (path);
150 /* switch (access) {
151 case FileIOPermissionAccess.AllAccess:
152 readList.Add (path);
153 writeList.Add (path);
154 appendList.Add (path);
155 pathList.Add (path);
156 break;
157 case FileIOPermissionAccess.NoAccess:
158 // ??? unit tests doesn't show removal using NoAccess ???
159 break;
160 case FileIOPermissionAccess.Read:
161 readList.Add (path);
162 break;
163 case FileIOPermissionAccess.Write:
164 writeList.Add (path);
165 break;
166 case FileIOPermissionAccess.Append:
167 appendList.Add (path);
168 break;
169 case FileIOPermissionAccess.PathDiscovery:
170 pathList.Add (path);
171 break;
172 default:
173 ThrowInvalidFlag (access, true);
174 break;
177 if ((access & FileIOPermissionAccess.Read) == FileIOPermissionAccess.Read)
178 readList.Add (path);
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)
184 pathList.Add (path);
187 public override IPermission Copy ()
189 if (m_Unrestricted)
190 return new FileIOPermission (PermissionState.Unrestricted);
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;
199 return copy;
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)) {
210 m_Unrestricted = true;
212 else{
213 m_Unrestricted = false;
214 string fileList = esd.Attribute ("Read");
215 string[] files;
216 if (fileList != null){
217 files = fileList.Split (';');
218 AddPathList (FileIOPermissionAccess.Read, files);
220 fileList = esd.Attribute ("Write");
221 if (fileList != null){
222 files = fileList.Split (';');
223 AddPathList (FileIOPermissionAccess.Write, files);
225 fileList = esd.Attribute ("Append");
226 if (fileList != null){
227 files = fileList.Split (';');
228 AddPathList (FileIOPermissionAccess.Append, files);
230 fileList = esd.Attribute ("PathDiscovery");
231 if (fileList != null){
232 files = fileList.Split (';');
233 AddPathList (FileIOPermissionAccess.PathDiscovery, files);
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
244 //type is array. I think docs are wrong and it just returns an array
245 ArrayList result = new ArrayList ();
246 switch (access) {
247 case FileIOPermissionAccess.NoAccess:
248 break;
249 case FileIOPermissionAccess.Read:
250 result.AddRange (readList);
251 break;
252 case FileIOPermissionAccess.Write:
253 result.AddRange (writeList);
254 break;
255 case FileIOPermissionAccess.Append:
256 result.AddRange (appendList);
257 break;
258 case FileIOPermissionAccess.PathDiscovery:
259 result.AddRange (pathList);
260 break;
261 default:
262 ThrowInvalidFlag (access, false);
263 break;
265 return (result.Count > 0) ? (string[]) result.ToArray (typeof (string)) : null;
268 public override IPermission Intersect (IPermission target)
270 FileIOPermission fiop = Cast (target);
271 if (fiop == null)
272 return null;
274 if (IsUnrestricted ())
275 return fiop.Copy ();
276 if (fiop.IsUnrestricted ())
277 return Copy ();
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);
295 if (fiop == null)
296 return false;
297 if (fiop.IsEmpty ())
298 return IsEmpty ();
300 if (IsUnrestricted ())
301 return fiop.IsUnrestricted ();
302 else if (fiop.IsUnrestricted ())
303 return true;
305 if ((m_AllFilesAccess & fiop.AllFiles) != m_AllFilesAccess)
306 return false;
307 if ((m_AllLocalFilesAccess & fiop.AllLocalFiles) != m_AllLocalFilesAccess)
308 return false;
310 if (!KeyIsSubsetOf (appendList, fiop.appendList))
311 return false;
312 if (!KeyIsSubsetOf (readList, fiop.readList))
313 return false;
314 if (!KeyIsSubsetOf (writeList, fiop.writeList))
315 return false;
316 if (!KeyIsSubsetOf (pathList, fiop.pathList))
317 return false;
319 return true;
322 public bool IsUnrestricted ()
324 return m_Unrestricted;
327 public void SetPathList (FileIOPermissionAccess access, string path)
329 if ((FileIOPermissionAccess.AllAccess & access) != access)
330 ThrowInvalidFlag (access, true);
331 ThrowIfInvalidPath (path);
332 // note: throw before clearing the actual list
333 Clear (access);
334 AddPathInternal (access, path);
337 public void SetPathList (FileIOPermissionAccess access, string[] pathList)
339 if ((FileIOPermissionAccess.AllAccess & access) != access)
340 ThrowInvalidFlag (access, true);
341 ThrowIfInvalidPath (pathList);
342 // note: throw before clearing the actual list
343 Clear (access);
344 foreach (string path in pathList)
345 AddPathInternal (access, path);
348 public override SecurityElement ToXml ()
350 SecurityElement se = Element (1);
351 if (m_Unrestricted) {
352 se.AddAttribute ("Unrestricted", "true");
354 else {
355 string[] paths = GetPathList (FileIOPermissionAccess.Append);
356 if (null != paths && paths.Length > 0) {
357 se.AddAttribute ("Append", String.Join (";", paths));
359 paths = GetPathList (FileIOPermissionAccess.Read);
360 if (null != paths && paths.Length > 0) {
361 se.AddAttribute ("Read", String.Join (";", paths));
363 paths = GetPathList (FileIOPermissionAccess.Write);
364 if (null != paths && paths.Length > 0) {
365 se.AddAttribute ("Write", String.Join (";", paths));
367 paths = GetPathList (FileIOPermissionAccess.PathDiscovery);
368 if (null != paths && paths.Length > 0) {
369 se.AddAttribute ("PathDiscovery", String.Join (";", paths));
372 return se;
375 public override IPermission Union (IPermission other)
377 FileIOPermission fiop = Cast (other);
378 if (fiop == null)
379 return Copy ();
381 if (IsUnrestricted () || fiop.IsUnrestricted ())
382 return new FileIOPermission (PermissionState.Unrestricted);
384 if (IsEmpty () && fiop.IsEmpty ())
385 return null;
387 FileIOPermission result = (FileIOPermission) Copy ();
388 result.AllFiles |= fiop.AllFiles;
389 result.AllLocalFiles |= fiop.AllLocalFiles;
391 string[] paths = fiop.GetPathList (FileIOPermissionAccess.Read);
392 if (paths != null)
393 UnionKeys (result.readList, paths);
395 paths = fiop.GetPathList (FileIOPermissionAccess.Write);
396 if (paths != null)
397 UnionKeys (result.writeList, paths);
399 paths = fiop.GetPathList (FileIOPermissionAccess.Append);
400 if (paths != null)
401 UnionKeys (result.appendList, paths);
403 paths = fiop.GetPathList (FileIOPermissionAccess.PathDiscovery);
404 if (paths != null)
405 UnionKeys (result.pathList, paths);
407 return result;
410 #if NET_2_0
411 [MonoTODO]
412 public override bool Equals (object obj)
414 return false;
417 [MonoTODO]
418 public override int GetHashCode ()
420 return base.GetHashCode ();
422 #endif
424 // IBuiltInPermission
425 int IBuiltInPermission.GetTokenIndex ()
427 return (int) BuiltInToken.FileIO;
430 // helpers
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)
440 if (target == null)
441 return null;
443 FileIOPermission fiop = (target as FileIOPermission);
444 if (fiop == null) {
445 ThrowInvalidPermission (target, typeof (FileIOPermission));
448 return fiop;
451 internal void ThrowInvalidFlag (FileIOPermissionAccess access, bool context)
453 string msg = null;
454 if (context)
455 msg = Locale.GetText ("Unknown flag '{0}'.");
456 else
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) {
464 string msg = String.Format (Locale.GetText ("Invalid characters in path: '{0}'"), path);
465 throw new ArgumentException (msg, "path");
467 // LAMESPEC: docs don't say it must be a rooted path, but the MS implementation enforces it, so we will too.
468 if (!Path.IsPathRooted (path)) {
469 string msg = Locale.GetText ("Absolute path information is required.");
470 throw new ArgumentException (msg, "path");
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)
484 readList.Clear ();
485 if ((access & FileIOPermissionAccess.Write) == FileIOPermissionAccess.Write)
486 writeList.Clear ();
487 if ((access & FileIOPermissionAccess.Append) == FileIOPermissionAccess.Append)
488 appendList.Clear ();
489 if ((access & FileIOPermissionAccess.PathDiscovery) == FileIOPermissionAccess.PathDiscovery)
490 pathList.Clear ();
493 internal bool KeyIsSubsetOf (IList local, IList target)
495 bool result = false;
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))) {
500 result = true;
501 break;
504 if (!result)
505 return false;
507 return true;
510 internal void UnionKeys (IList list, string[] paths)
512 foreach (string p in paths) {
513 // c14n
514 string path = Path.GetFullPath (p);
515 int len = list.Count;
516 if (len == 0) {
517 list.Add (path);
519 else {
520 for (int i=0; i < len; i++) {
521 // c14n
522 string s = Path.GetFullPath ((string) list [i]);
523 if (s.StartsWith (path)) {
524 // replace (with reduced version)
525 list [i] = path;
526 break;
528 else if (path.StartsWith (s)) {
529 // no need to add
530 break;
532 else {
533 list.Add (path);
534 break;
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))
547 result.Add (t);
549 else {
550 if (l.StartsWith (t))
551 result.Add (l);