2004-07-14 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / corlib / System.Security.Permissions / FileIOPermission.cs
1 //------------------------------------------------------------------------------\r
2 // \r
3 // System.Security.Permissions.FileIOPermission.cs \r
4 //\r
5 // Copyright (C) 2001 Nick Drochak, All Rights Reserved\r
6 // \r
7 // Author:         Nick Drochak, ndrochak@gol.com\r
8 // Created:        2002-01-09 \r
9 //\r
10 //------------------------------------------------------------------------------\r
11
12 //
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34 \r
35 using System.Collections;\r
36 using System.IO;\r
37 using System.Text;\r
38 \r
39 namespace System.Security.Permissions {\r
40 \r
41         [Serializable]\r
42         public sealed class FileIOPermission\r
43                 : CodeAccessPermission, IBuiltInPermission, IUnrestrictedPermission {\r
44 \r
45                 private static char[] m_badCharacters = {'\"','<', '>', '|', '*', '?'};\r
46                 private bool m_Unrestricted = false;\r
47                 private Hashtable m_PathList = new Hashtable();\r
48                 private FileIOPermissionAccess m_AllFilesAccess = FileIOPermissionAccess.NoAccess;\r
49                 private FileIOPermissionAccess m_AllLocalFilesAccess = FileIOPermissionAccess.NoAccess;\r
50 \r
51                 public FileIOPermission(PermissionState state) {\r
52                         if (!Enum.IsDefined(typeof(PermissionState), state)){\r
53                                 throw new ArgumentException("Invalid permission state.", "state");\r
54                         }\r
55                         m_Unrestricted = (PermissionState.Unrestricted == state);\r
56                         if (m_Unrestricted) {\r
57                                 m_AllFilesAccess = FileIOPermissionAccess.AllAccess;\r
58                                 m_AllLocalFilesAccess = FileIOPermissionAccess.AllAccess;\r
59                         }\r
60                 }\r
61 \r
62                 public FileIOPermission(FileIOPermissionAccess access, string path)
63                 {
64                         if (path == null)
65                                 throw new ArgumentNullException ("path");
66 \r
67                         if ((FileIOPermissionAccess.AllAccess & access) != access){\r
68                                 throw new ArgumentException("Illegal enum value: "+access.ToString()+".");\r
69                         }\r
70 \r
71                         if (path.LastIndexOfAny(m_badCharacters) >= 0){\r
72                                 throw new ArgumentException("Illegal characters found in input.  Security checks can not contain wild card characters.", "path");\r
73                         }\r
74                         \r
75                         AddPathList(access, path);\r
76                 }\r
77 \r
78                 public FileIOPermission(FileIOPermissionAccess access, string[] pathList)
79                 {\r
80                         if (pathList == null)
81                                 throw new ArgumentNullException ("pathList");
82
83                         if ((FileIOPermissionAccess.AllAccess & access) != access){\r
84                                 throw new ArgumentException("Illegal enum value: "+access.ToString()+".");\r
85                         }\r
86 \r
87                         AddPathList(access, pathList);\r
88                 }\r
89 \r
90                 public FileIOPermissionAccess AllFiles {\r
91                         get {\r
92                                 return m_AllFilesAccess;\r
93                         } \r
94                         set {\r
95                                 // if we are already set to unrestricted, don't change this property\r
96                                 if (!m_Unrestricted){\r
97                                         m_AllFilesAccess = value;\r
98                                 }\r
99                         }\r
100                 }\r
101 \r
102                 public FileIOPermissionAccess AllLocalFiles {\r
103                         get {\r
104                                 return m_AllLocalFilesAccess;\r
105                         } \r
106                         set {\r
107                                 // if we are already set to unrestricted, don't change this property\r
108                                 if (!m_Unrestricted){\r
109                                         m_AllLocalFilesAccess = value;\r
110                                 }\r
111                         }\r
112                 }\r
113 \r
114                 public void AddPathList(FileIOPermissionAccess access, string path){\r
115                         if ((FileIOPermissionAccess.AllAccess & access) != access){\r
116                                 throw new ArgumentException("Illegal enum value: {0}.",access.ToString());\r
117                         }\r
118 \r
119                         if (path.LastIndexOfAny(m_badCharacters) >= 0){\r
120                                 throw new ArgumentException("Invalid characters in path: '{0}'", path);\r
121                         }\r
122 \r
123                         // LAMESPEC: docs don't say it must be a rooted path, but the MS implementation enforces it, so we will too.\r
124                         if(!Path.IsPathRooted(path)) {\r
125                                 throw new ArgumentException("Absolute path information is required.");\r
126                         }\r
127 \r
128                         // don't add the same path twice, instead overwrite access entry for that path\r
129                         if (m_PathList.ContainsKey(path)) {\r
130                                 FileIOPermissionAccess currentPermission = (FileIOPermissionAccess)m_PathList[path];\r
131                                 currentPermission |= access;\r
132                                 m_PathList[path] = currentPermission;\r
133                         }\r
134                         else {\r
135                                 m_PathList.Add(path, access);\r
136                         }\r
137                 }\r
138 \r
139                 public void AddPathList(FileIOPermissionAccess access, string[] pathList        ){\r
140                         foreach(string path in pathList){\r
141                                 AddPathList(access, path);\r
142                         }\r
143                         \r
144                 }\r
145 \r
146                 // private constructor used by Copy() method\r
147                 private FileIOPermission(Hashtable pathList, FileIOPermissionAccess allFiles, \r
148                                                 FileIOPermissionAccess allLocalFiles, bool unrestricted){\r
149                         m_PathList = pathList;\r
150                         m_AllFilesAccess = allFiles;\r
151                         m_AllLocalFilesAccess = allLocalFiles;\r
152                         m_Unrestricted = unrestricted;\r
153                 }\r
154 \r
155                 public override IPermission Copy(){\r
156                         if (m_Unrestricted) {\r
157                                 return new FileIOPermission(PermissionState.Unrestricted);\r
158                         }\r
159                         else{\r
160                                 FileIOPermission retVal = new FileIOPermission(m_PathList, m_AllFilesAccess, m_AllLocalFilesAccess, m_Unrestricted);\r
161                                 return retVal;\r
162                         }\r
163                 }\r
164 \r
165                 /*  XML Schema for FileIOPermission\r
166                                 <IPermission class=\94FileIOPermission\94 \r
167                                                                  version=\941\94\r
168                                                                  (\r
169                                                                  Read=\94[list of files or folders]\94 | \r
170                                                                  Write=\94[list of files or folders]\94 |\r
171                                                                  Append=\94[list of files or folders]\94   \r
172                                                                  ) v Unrestricted=\94true\94 \r
173                                                                  />\r
174                 */\r
175                 public override void FromXml(SecurityElement esd){\r
176                         if (null == esd) {\r
177                                 throw new ArgumentNullException();\r
178                         }\r
179                         if (esd.Tag != "IPermission" || (string)esd.Attributes["class"] != "FileIOPermission"\r
180                                         || (string)esd.Attributes["version"] != "1"){\r
181                                 throw new ArgumentException("Not a valid permission element");\r
182                         }\r
183                         m_PathList.Clear();\r
184                         if ("true" == (string)esd.Attributes["Unrestricted"]){\r
185                                 m_Unrestricted = true;\r
186                         }\r
187                         else{\r
188                                 m_Unrestricted = false;\r
189                                 string fileList;\r
190                                 fileList = (string)esd.Attributes["Read"];\r
191                                 string[] files;\r
192                                 if (fileList != null){\r
193                                         files = fileList.Split(';');\r
194                                         AddPathList(FileIOPermissionAccess.Read, files);\r
195                                 }\r
196                                 fileList = (string)esd.Attributes["Write"];\r
197                                 if (fileList != null){\r
198                                         files = fileList.Split(';');\r
199                                         AddPathList(FileIOPermissionAccess.Write, files);\r
200                                 }\r
201                                 fileList = (string)esd.Attributes["Append"];\r
202                                 if (fileList != null){\r
203                                         files = fileList.Split(';');\r
204                                         AddPathList(FileIOPermissionAccess.Append, files);\r
205                                 }\r
206                         }\r
207                 }\r
208 \r
209                 public string[] GetPathList(FileIOPermissionAccess access){\r
210                         //LAMESPEC: docs says it returns (semicolon separated) list, but return\r
211                         //type is array.  I think docs are wrong and it just returns an array\r
212                         if ((FileIOPermissionAccess.AllAccess & access) != access){\r
213                                 throw new ArgumentException("Illegal enum value: "+access.ToString()+".");\r
214                         }\r
215 \r
216                         ArrayList matchingPaths = new ArrayList();\r
217                         System.Collections.IDictionaryEnumerator pathListIterator = m_PathList.GetEnumerator();\r
218                         while (pathListIterator.MoveNext()) {\r
219                                 if (((FileIOPermissionAccess)pathListIterator.Value & access) != 0) {\r
220                                         matchingPaths.Add((string)pathListIterator.Key);\r
221                                 }\r
222                         }\r
223                         if (matchingPaths.Count == 0) {\r
224                                 return null;\r
225                         }\r
226                         else {\r
227                                 return (string[])matchingPaths.ToArray(typeof(string));\r
228                         }\r
229                 }\r
230 \r
231                 public override IPermission Intersect(IPermission target){ \r
232                         if (null == target){\r
233                                 return null;\r
234                         }\r
235                         else {\r
236                                 if (target.GetType() != typeof(FileIOPermission)){\r
237                                         throw new ArgumentException();\r
238                                 }\r
239                         }\r
240                         FileIOPermission FIOPTarget = (FileIOPermission)target;\r
241                         if (FIOPTarget.IsUnrestricted() && m_Unrestricted){\r
242                                 return new FileIOPermission(PermissionState.Unrestricted);\r
243                         }\r
244                         else if (FIOPTarget.IsUnrestricted()){\r
245                                 return Copy();\r
246                         }\r
247                         else if (m_Unrestricted){\r
248                                 return FIOPTarget.Copy();\r
249                         }\r
250                         else{\r
251                                 FileIOPermission retVal = new FileIOPermission(PermissionState.None);\r
252                                 retVal.AllFiles = m_AllFilesAccess & FIOPTarget.AllFiles;\r
253                                 retVal.AllLocalFiles = m_AllLocalFilesAccess & FIOPTarget.AllLocalFiles;\r
254 \r
255                                 string[] paths;\r
256                                 paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Append);\r
257                                 if (null != paths) {\r
258                                         foreach (string path in paths){\r
259                                                 if (m_PathList.ContainsKey(path) \r
260                                                         && ((FileIOPermissionAccess)m_PathList[path] & FileIOPermissionAccess.Append) != 0){\r
261                                                         retVal.AddPathList(FileIOPermissionAccess.Append, path);\r
262                                                 }\r
263                                         }\r
264                                 }\r
265 \r
266                                 paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Read);\r
267                                 if (null != paths) {\r
268                                         foreach (string path in paths){\r
269                                                 if (m_PathList.ContainsKey(path) \r
270                                                         && ((FileIOPermissionAccess)m_PathList[path] & FileIOPermissionAccess.Read) != 0){\r
271                                                         retVal.AddPathList(FileIOPermissionAccess.Read, path);\r
272                                                 }\r
273                                         }\r
274                                 }\r
275 \r
276                                 paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Write);\r
277                                 if (null != paths) {\r
278                                         foreach (string path in paths){\r
279                                                 if (m_PathList.ContainsKey(path) \r
280                                                         && ((FileIOPermissionAccess)m_PathList[path] & FileIOPermissionAccess.Write) != 0){\r
281                                                         retVal.AddPathList(FileIOPermissionAccess.Write, path);\r
282                                                 }\r
283                                         }\r
284                                 }\r
285 \r
286                                 return retVal;\r
287                         }\r
288                 }\r
289 \r
290 \r
291                 public override bool IsSubsetOf(IPermission target){\r
292                         // X.IsSubsetOf(Y) is true if permission Y includes everything allowed by X.\r
293                         if (target != null && target.GetType() != typeof(FileIOPermission)){\r
294                                 throw new ArgumentException();\r
295                         }\r
296                         FileIOPermission FIOPTarget = (FileIOPermission)target;\r
297                         if (FIOPTarget.IsUnrestricted()){\r
298                                 return true;\r
299                         }\r
300                         else if (m_Unrestricted){\r
301                                 return false;\r
302                         }\r
303                         else if ((m_AllFilesAccess & FIOPTarget.AllFiles) != m_AllFilesAccess) {\r
304                                 return false;\r
305                         }\r
306                         else if ((m_AllLocalFilesAccess & FIOPTarget.AllLocalFiles) != m_AllLocalFilesAccess) {\r
307                                 return false;\r
308                         }\r
309                         else{\r
310                                 string[] pathsNeeded;\r
311                                 string[] pathsInTarget;\r
312 \r
313                                 pathsNeeded = GetPathList(FileIOPermissionAccess.Append);\r
314                                 if (null != pathsNeeded) {\r
315                                         pathsInTarget = FIOPTarget.GetPathList(FileIOPermissionAccess.Append);\r
316                                         foreach (string path in pathsNeeded){\r
317                                                 if (Array.IndexOf(pathsInTarget, path) <0) {\r
318                                                         return false;\r
319                                                 }\r
320                                         }\r
321                                 }\r
322 \r
323                                 pathsNeeded = GetPathList(FileIOPermissionAccess.Read);\r
324                                 if (null != pathsNeeded) {\r
325                                         pathsInTarget = FIOPTarget.GetPathList(FileIOPermissionAccess.Read);\r
326                                         foreach (string path in pathsNeeded){\r
327                                                 if (Array.IndexOf(pathsInTarget, path) <0) {\r
328                                                         return false;\r
329                                                 }\r
330                                         }\r
331                                 }\r
332 \r
333                                 pathsNeeded = GetPathList(FileIOPermissionAccess.Write);\r
334                                 if (null != pathsNeeded) {\r
335                                         pathsInTarget = FIOPTarget.GetPathList(FileIOPermissionAccess.Write);\r
336                                         foreach (string path in pathsNeeded){\r
337                                                 if (Array.IndexOf(pathsInTarget, path) <0) {\r
338                                                         return false;\r
339                                                 }\r
340                                         }\r
341                                 }\r
342 \r
343                                 return true;\r
344                         }\r
345                 }\r
346 \r
347                 public bool IsUnrestricted(){\r
348                         return m_Unrestricted;\r
349                 }\r
350 \r
351                 public void SetPathList(FileIOPermissionAccess access, string path){\r
352                         if ((FileIOPermissionAccess.AllAccess & access) != access){\r
353                                 throw new ArgumentException("Illegal enum value: "+access.ToString()+".");\r
354                         }\r
355                         if (path.LastIndexOfAny(m_badCharacters) >= 0){\r
356                                 throw new ArgumentException("Invalid characters in path: '{0}'", path);\r
357                         }\r
358 \r
359                         m_PathList.Clear();\r
360                         AddPathList(access, path);\r
361                 }\r
362                 \r
363                 public void SetPathList(FileIOPermissionAccess access, string[] pathList){\r
364                         if ((FileIOPermissionAccess.AllAccess & access) != access){\r
365                                 throw new ArgumentException("Illegal enum value: "+access.ToString()+".");\r
366                         }\r
367                         foreach(string path in pathList){\r
368                                 if (path.LastIndexOfAny(m_badCharacters) >= 0){\r
369                                         throw new ArgumentException("Invalid characters in path entry: '{0}'", path);\r
370                                 }\r
371                         }\r
372 \r
373                         m_PathList.Clear();\r
374                         AddPathList(access, pathList);\r
375                 }\r
376 \r
377                 public override SecurityElement ToXml(){\r
378                         //Encode the the current permission to XML using the \r
379                         //security element class.\r
380                         SecurityElement element = new SecurityElement("IPermission");\r
381                         Type type = this.GetType();\r
382                         StringBuilder AsmName = new StringBuilder(type.Assembly.ToString());\r
383                         AsmName.Replace('\"', '\'');\r
384                         element.AddAttribute("class", type.FullName + ", " + AsmName);\r
385                         element.AddAttribute("version", "1");\r
386                         if(m_Unrestricted){\r
387                                 element.AddAttribute("Unrestricted", "true");\r
388                         }\r
389                         else {\r
390                                 string[] paths;\r
391                                 paths = GetPathList(FileIOPermissionAccess.Append);\r
392                                 if (null != paths && paths.Length >0){\r
393                                         element.AddAttribute("Append", String.Join(";",paths));\r
394                                 }\r
395                                 paths = GetPathList(FileIOPermissionAccess.Read);\r
396                                 if (null != paths && paths.Length >0){\r
397                                         element.AddAttribute("Read", String.Join(";",paths));\r
398                                 }\r
399                                 paths = GetPathList(FileIOPermissionAccess.Write);\r
400                                 if (null != paths && paths.Length >0){\r
401                                         element.AddAttribute("Write", String.Join(";",paths));\r
402                                 }\r
403                         }\r
404                         return element;\r
405                 }\r
406 \r
407                 public override IPermission Union(IPermission other){\r
408                         if (null == other){\r
409                                 return null;\r
410                         }\r
411                         else {\r
412                                 if (other.GetType() != typeof(FileIOPermission)){\r
413                                         throw new ArgumentException();\r
414                                 }\r
415                         }\r
416                         FileIOPermission FIOPTarget = (FileIOPermission)other;\r
417                         if (FIOPTarget.IsUnrestricted() || m_Unrestricted){\r
418                                 return new FileIOPermission(PermissionState.Unrestricted);\r
419                         }\r
420                         else{\r
421                                 FileIOPermission retVal = (FileIOPermission)Copy();\r
422                                 retVal.AllFiles |= FIOPTarget.AllFiles;\r
423                                 retVal.AllLocalFiles |= FIOPTarget.AllLocalFiles;\r
424                                 string[] paths;\r
425                                 paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Append);\r
426                                 if (null != paths){\r
427                                                 retVal.AddPathList(FileIOPermissionAccess.Append, paths);\r
428                                 }\r
429                                 paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Read);\r
430                                 if (null != paths){\r
431                                         retVal.AddPathList(FileIOPermissionAccess.Read, paths);\r
432                                 }\r
433                                 paths = FIOPTarget.GetPathList(FileIOPermissionAccess.Write);\r
434                                 if (null != paths){\r
435                                         retVal.AddPathList(FileIOPermissionAccess.Write, paths);\r
436                                 }\r
437                                 return retVal;\r
438                         }\r
439                 }\r
440 \r
441                 // IBuiltInPermission\r
442                 int IBuiltInPermission.GetTokenIndex ()\r
443                 {\r
444                         return 2;\r
445                 }\r
446         }\r
447 }\r