disable broken tests on net_4_0
[mcs.git] / class / corlib / System.Security.Permissions / FileIOPermission.cs
blob1d685ea757d6b16e3f3cb4acc37293ac9681aec2
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-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:
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 using System.Runtime.InteropServices;
36 using System.Security.AccessControl;
38 namespace System.Security.Permissions {
40 [ComVisible (true)]
41 [Serializable]
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;
72 CreateLists ();
75 public FileIOPermission (FileIOPermissionAccess access, string path)
77 if (path == null)
78 throw new ArgumentNullException ("path");
80 CreateLists ();
81 // access and path will be validated in AddPathList
82 AddPathList (access, path);
85 public FileIOPermission (FileIOPermissionAccess access, string[] pathList)
87 if (pathList == null)
88 throw new ArgumentNullException ("pathList");
90 CreateLists ();
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; }
117 set {
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; }
127 set {
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)
160 readList.Add (path);
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)
166 pathList.Add (path);
169 public override IPermission Copy ()
171 if (m_Unrestricted)
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;
181 return copy;
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;
194 else{
195 m_Unrestricted = false;
196 string fileList = esd.Attribute ("Read");
197 string[] files;
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 ();
226 switch (access) {
227 case FileIOPermissionAccess.NoAccess:
228 break;
229 case FileIOPermissionAccess.Read:
230 result.AddRange (readList);
231 break;
232 case FileIOPermissionAccess.Write:
233 result.AddRange (writeList);
234 break;
235 case FileIOPermissionAccess.Append:
236 result.AddRange (appendList);
237 break;
238 case FileIOPermissionAccess.PathDiscovery:
239 result.AddRange (pathList);
240 break;
241 default:
242 ThrowInvalidFlag (access, false);
243 break;
245 return (result.Count > 0) ? (string[]) result.ToArray (typeof (string)) : null;
248 public override IPermission Intersect (IPermission target)
250 FileIOPermission fiop = Cast (target);
251 if (fiop == null)
252 return null;
254 if (IsUnrestricted ())
255 return fiop.Copy ();
256 if (fiop.IsUnrestricted ())
257 return Copy ();
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);
274 if (fiop == null)
275 return false;
276 if (fiop.IsEmpty ())
277 return IsEmpty ();
279 if (IsUnrestricted ())
280 return fiop.IsUnrestricted ();
281 else if (fiop.IsUnrestricted ())
282 return true;
284 if ((m_AllFilesAccess & fiop.AllFiles) != m_AllFilesAccess)
285 return false;
286 if ((m_AllLocalFilesAccess & fiop.AllLocalFiles) != m_AllLocalFilesAccess)
287 return false;
289 if (!KeyIsSubsetOf (appendList, fiop.appendList))
290 return false;
291 if (!KeyIsSubsetOf (readList, fiop.readList))
292 return false;
293 if (!KeyIsSubsetOf (writeList, fiop.writeList))
294 return false;
295 if (!KeyIsSubsetOf (pathList, fiop.pathList))
296 return false;
298 return true;
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
312 Clear (access);
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
322 Clear (access);
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");
333 else {
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));
351 return se;
354 public override IPermission Union (IPermission other)
356 FileIOPermission fiop = Cast (other);
357 if (fiop == null)
358 return Copy ();
360 if (IsUnrestricted () || fiop.IsUnrestricted ())
361 return new FileIOPermission (PermissionState.Unrestricted);
363 if (IsEmpty () && fiop.IsEmpty ())
364 return null;
366 FileIOPermission result = (FileIOPermission) Copy ();
367 result.AllFiles |= fiop.AllFiles;
368 result.AllLocalFiles |= fiop.AllLocalFiles;
370 string[] paths = fiop.GetPathList (FileIOPermissionAccess.Read);
371 if (paths != null)
372 UnionKeys (result.readList, paths);
374 paths = fiop.GetPathList (FileIOPermissionAccess.Write);
375 if (paths != null)
376 UnionKeys (result.writeList, paths);
378 paths = fiop.GetPathList (FileIOPermissionAccess.Append);
379 if (paths != null)
380 UnionKeys (result.appendList, paths);
382 paths = fiop.GetPathList (FileIOPermissionAccess.PathDiscovery);
383 if (paths != null)
384 UnionKeys (result.pathList, paths);
386 return result;
389 [MonoTODO ("(2.0)")]
390 [ComVisible (false)]
391 public override bool Equals (object obj)
393 return false;
396 [MonoTODO ("(2.0)")]
397 [ComVisible (false)]
398 public override int GetHashCode ()
400 return base.GetHashCode ();
403 // IBuiltInPermission
404 int IBuiltInPermission.GetTokenIndex ()
406 return (int) BuiltInToken.FileIO;
409 // helpers
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)
419 if (target == null)
420 return null;
422 FileIOPermission fiop = (target as FileIOPermission);
423 if (fiop == null) {
424 ThrowInvalidPermission (target, typeof (FileIOPermission));
427 return fiop;
430 internal static void ThrowInvalidFlag (FileIOPermissionAccess access, bool context)
432 string msg = null;
433 if (context)
434 msg = Locale.GetText ("Unknown flag '{0}'.");
435 else
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)
470 readList.Clear ();
471 if ((access & FileIOPermissionAccess.Write) == FileIOPermissionAccess.Write)
472 writeList.Clear ();
473 if ((access & FileIOPermissionAccess.Append) == FileIOPermissionAccess.Append)
474 appendList.Clear ();
475 if ((access & FileIOPermissionAccess.PathDiscovery) == FileIOPermissionAccess.PathDiscovery)
476 pathList.Clear ();
479 // note: all path in IList are already "full paths"
480 internal static bool KeyIsSubsetOf (IList local, IList target)
482 bool result = false;
483 foreach (string l in local) {
484 foreach (string t in target) {
485 if (Path.IsPathSubsetOf (t, l)) {
486 result = true;
487 break;
490 if (!result)
491 return false;
493 return true;
496 internal static void UnionKeys (IList list, string[] paths)
498 foreach (string path in paths) {
499 int len = list.Count;
500 if (len == 0) {
501 list.Add (path);
503 else {
504 int i;
505 for (i=0; i < len; i++) {
506 string s = (string) list [i];
507 if (Path.IsPathSubsetOf (path, s)) {
508 // replace (with reduced version)
509 list [i] = path;
510 break;
512 else if (Path.IsPathSubsetOf (s, path)) {
513 // no need to add
514 break;
517 if (i == len) {
518 list.Add (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))
530 result.Add (t);
532 else {
533 if (Path.IsPathSubsetOf (t, l))
534 result.Add (l);