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
))