[runtime] Don't reset abort exception in invoke wrapper
[mono.git] / mcs / class / System.Core / System.IO.MemoryMappedFiles / MemoryMappedFile.cs
1 //
2 // MemoryMappedFile.cs
3 //
4 // Authors:
5 //      Zoltan Varga (vargaz@gmail.com)
6 //
7 // Copyright (C) 2009, Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30 using System.IO;
31 using System.Collections.Generic;
32 using Microsoft.Win32.SafeHandles;
33 using System.Runtime.InteropServices;
34 using System.Runtime.CompilerServices;
35
36
37 namespace System.IO.MemoryMappedFiles
38 {
39         internal static class MemoryMapImpl {
40                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
41                 static extern IntPtr OpenFileInternal (string path, FileMode mode, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, out int error);
42
43                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
44                 static extern IntPtr OpenHandleInternal (IntPtr handle, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, out int error);
45
46                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
47                 internal extern static void CloseMapping (IntPtr handle);
48
49                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
50                 internal extern static void Flush (IntPtr file_handle);
51
52                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
53                 internal extern static void ConfigureHandleInheritability (IntPtr handle, HandleInheritability inheritability);
54
55                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
56                 internal extern static bool Unmap (IntPtr mmap_handle);
57
58                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
59                 extern static int MapInternal (IntPtr handle, long offset, ref long size, MemoryMappedFileAccess access, out IntPtr mmap_handle, out IntPtr base_address);
60
61                 internal static void Map (IntPtr handle, long offset, ref long size, MemoryMappedFileAccess access, out IntPtr mmap_handle, out IntPtr base_address)
62                 {
63                         int error = MapInternal (handle, offset, ref size, access, out mmap_handle, out base_address);
64                         if (error != 0)
65                                 throw CreateException (error, "<none>");
66                 }
67
68                 static Exception CreateException (int error, string path) {
69                         switch (error){
70                         case 1:
71                                 return new ArgumentException ("A positive capacity must be specified for a Memory Mapped File backed by an empty file.");
72                         case 2:
73                                 return new ArgumentOutOfRangeException ("capacity", "The capacity may not be smaller than the file size.");
74                         case 3:
75                                 return new FileNotFoundException (path);
76                         case 4:
77                                 return new IOException ("The file already exists");
78                         case 5:
79                                 return new PathTooLongException ();
80                         case 6:
81                                 return new IOException ("Could not open file");
82                         case 7:
83                                 return new ArgumentException ("Capacity must be bigger than zero for non-file mappings");
84                         case 8:
85                                 return new ArgumentException ("Invalid FileMode value.");
86                         case 9:
87                                 return new IOException ("Could not map file");
88                         case 10:
89                                 return new UnauthorizedAccessException ("Access to the path is denied.");
90                         case 11:
91                                 return new ArgumentOutOfRangeException ("capacity", "The capacity cannot be greater than the size of the system's logical address space.");
92                         default:
93                                 return new IOException ("Failed with unknown error code " + error);
94                         }
95                 }
96
97                 internal static IntPtr OpenFile (string path, FileMode mode, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options)
98                 {
99                         int error = 0;
100                         IntPtr res = OpenFileInternal (path, mode, mapName, out capacity, access, options, out error);
101                         if (error != 0)
102                                 throw CreateException (error, path);
103                         return res;
104                 }
105
106                 internal static IntPtr OpenHandle (IntPtr handle, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options)
107                 {
108                         int error = 0;
109                         IntPtr res = OpenHandleInternal (handle, mapName, out capacity, access, options, out error);
110                         if (error != 0)
111                                 throw CreateException (error, "<none>");
112                         return res;
113                 }
114         }
115
116
117         public class MemoryMappedFile : IDisposable {
118                 // MemoryMappedFileAccess fileAccess;
119                 // string name;
120                 // long fileCapacity;
121
122                 //
123                 // We allow the use of either the FileStream/keepOpen combo
124                 // or a Unix file descriptor.  This way we avoid the dependency on
125                 // Mono's io-layer having the Unix file descriptors mapped to
126                 // the same io-layer handle
127                 //
128                 FileStream stream;
129                 bool keepOpen;
130                 IntPtr handle;
131
132                 public static MemoryMappedFile CreateFromFile (string path)
133                 {
134                         return CreateFromFile (path, FileMode.Open, null, 0, MemoryMappedFileAccess.ReadWrite);
135                 }
136
137                 public static MemoryMappedFile CreateFromFile (string path, FileMode mode)
138                 {
139                         long capacity = 0;
140                         if (path == null)
141                                 throw new ArgumentNullException ("path");
142                         if (path.Length == 0)
143                                 throw new ArgumentException ("path");
144                         if (mode == FileMode.Append)
145                                 throw new ArgumentException ("mode");
146
147                         IntPtr handle = MemoryMapImpl.OpenFile (path, mode, null, out capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None);
148
149                         return new MemoryMappedFile () {
150                                 handle = handle,
151                                 // fileAccess = MemoryMappedFileAccess.ReadWrite,
152                                 // fileCapacity = capacity
153                         };
154                 }
155
156                 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName)
157                 {
158                         return CreateFromFile (path, mode, mapName, 0, MemoryMappedFileAccess.ReadWrite);
159                 }
160
161                 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName, long capacity)
162                 {
163                         return CreateFromFile (path, mode, mapName, capacity, MemoryMappedFileAccess.ReadWrite);
164                 }
165
166                 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName, long capacity, MemoryMappedFileAccess access)
167                 {
168                         if (path == null)
169                                 throw new ArgumentNullException ("path");
170                         if (path.Length == 0)
171                                 throw new ArgumentException ("path");
172                         if (mapName != null && mapName.Length == 0)
173                                 throw new ArgumentException ("mapName");
174                         if (mode == FileMode.Append)
175                                 throw new ArgumentException ("mode");                   
176                         if (capacity < 0)
177                                 throw new ArgumentOutOfRangeException ("capacity");
178
179                         IntPtr handle = MemoryMapImpl.OpenFile (path, mode, mapName, out capacity, access, MemoryMappedFileOptions.None);
180                         
181                         return new MemoryMappedFile () {
182                                 handle = handle,
183                                 // fileAccess = access,
184                                 // name = mapName,
185                                 // fileCapacity = capacity
186                         };
187                 }
188
189                 public static MemoryMappedFile CreateFromFile (FileStream fileStream, string mapName, long capacity, MemoryMappedFileAccess access,
190                                                                HandleInheritability inheritability,
191                                                                bool leaveOpen)
192                 {
193                         if (fileStream == null)
194                                 throw new ArgumentNullException ("fileStream");
195                         if (mapName != null && mapName.Length == 0)
196                                 throw new ArgumentException ("mapName");
197                         if ((!MonoUtil.IsUnix && capacity == 0 && fileStream.Length == 0) || (capacity > fileStream.Length))
198                                 throw new ArgumentException ("capacity");
199
200                         IntPtr handle = MemoryMapImpl.OpenHandle (fileStream.SafeFileHandle.DangerousGetHandle (), mapName, out capacity, access, MemoryMappedFileOptions.None);
201                         
202                         MemoryMapImpl.ConfigureHandleInheritability (handle, inheritability);
203                                 
204                         return new MemoryMappedFile () {
205                                 handle = handle,
206                                 // fileAccess = access,
207                                 // name = mapName,
208                                 // fileCapacity = capacity,
209
210                                 stream = fileStream,
211                                 keepOpen = leaveOpen
212                         };
213                 }
214
215                 [MonoLimitation ("memoryMappedFileSecurity is currently ignored")]
216                 public static MemoryMappedFile CreateFromFile (FileStream fileStream, string mapName, long capacity, MemoryMappedFileAccess access,
217                                                                MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability inheritability,
218                                                                bool leaveOpen)
219                 {
220                         if (fileStream == null)
221                                 throw new ArgumentNullException ("fileStream");
222                         if (mapName != null && mapName.Length == 0)
223                                 throw new ArgumentException ("mapName");
224                         if ((!MonoUtil.IsUnix && capacity == 0 && fileStream.Length == 0) || (capacity > fileStream.Length))
225                                 throw new ArgumentException ("capacity");
226
227                         IntPtr handle = MemoryMapImpl.OpenHandle (fileStream.SafeFileHandle.DangerousGetHandle (), mapName, out capacity, access, MemoryMappedFileOptions.None);
228                         
229                         MemoryMapImpl.ConfigureHandleInheritability (handle, inheritability);
230                                 
231                         return new MemoryMappedFile () {
232                                 handle = handle,
233                                 // fileAccess = access,
234                                 // name = mapName,
235                                 // fileCapacity = capacity,
236
237                                 stream = fileStream,
238                                 keepOpen = leaveOpen
239                         };
240                 }
241
242
243                 static MemoryMappedFile CoreShmCreate (string mapName, long capacity, MemoryMappedFileAccess access,
244                                                           MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity,
245                                                           HandleInheritability inheritability, FileMode mode)
246                 {
247                         if (mapName != null && mapName.Length == 0)
248                                 throw new ArgumentException ("mapName");
249                         if (capacity < 0)
250                                 throw new ArgumentOutOfRangeException ("capacity");
251
252                         IntPtr handle = MemoryMapImpl.OpenFile (null, mode, mapName, out capacity, access, options);
253                         
254                         return new MemoryMappedFile () {
255                                 handle = handle,
256                                 // fileAccess = access,
257                                 // name = mapName,
258                                 // fileCapacity = capacity
259                         };                      
260                 }
261
262                 [MonoLimitation ("Named mappings scope is process local")]
263                 public static MemoryMappedFile CreateNew (string mapName, long capacity)
264                 {
265                         return CreateNew (mapName, capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, null, HandleInheritability.None);
266                 }
267
268                 [MonoLimitation ("Named mappings scope is process local")]
269                 public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access) 
270                 {
271                         return CreateNew (mapName, capacity, access, MemoryMappedFileOptions.None, null, HandleInheritability.None);
272                 }
273
274                 [MonoLimitation ("Named mappings scope is process local; options is ignored")]
275                 public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, HandleInheritability inheritability)
276                 {
277                         return CreateNew (mapName, capacity, access, options, null, inheritability);
278                 }
279
280                 [MonoLimitation ("Named mappings scope is process local; options and memoryMappedFileSecurity are ignored")]
281                 public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access,
282                                                           MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity,
283                                                           HandleInheritability inheritability)
284                 {
285                         return CoreShmCreate (mapName, capacity, access, options, memoryMappedFileSecurity, inheritability, FileMode.CreateNew);
286                 }
287
288                 [MonoLimitation ("Named mappings scope is process local")]
289                 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity)
290                 {
291                         return CreateOrOpen (mapName, capacity, MemoryMappedFileAccess.ReadWrite);
292                 }
293
294                 [MonoLimitation ("Named mappings scope is process local")]
295                 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access)
296                 {
297                         return CreateOrOpen (mapName, capacity, access, MemoryMappedFileOptions.None, null, HandleInheritability.None);
298                 }
299
300                 [MonoLimitation ("Named mappings scope is process local")]
301                 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, HandleInheritability inheritability)
302                 {
303                         return CreateOrOpen (mapName, capacity, access, options, null, inheritability);
304                 }
305
306                 [MonoLimitation ("Named mappings scope is process local")]
307                 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability inheritability)
308                 {
309                         return CoreShmCreate (mapName, capacity, access, options, memoryMappedFileSecurity, inheritability, FileMode.OpenOrCreate);
310                 }
311
312                 [MonoLimitation ("Named mappings scope is process local")]
313                 public static MemoryMappedFile OpenExisting (string mapName)
314                 {
315                         throw new NotImplementedException ();
316                 }
317
318                 [MonoLimitation ("Named mappings scope is process local")]
319                 public static MemoryMappedFile OpenExisting (string mapName, MemoryMappedFileRights desiredAccessRights)
320                 {
321                         throw new NotImplementedException ();
322                 }
323
324                 [MonoLimitation ("Named mappings scope is process local")]
325                 public static MemoryMappedFile OpenExisting (string mapName, MemoryMappedFileRights desiredAccessRights, HandleInheritability inheritability)
326                 {
327                         throw new NotImplementedException ();
328                 }
329
330                 public MemoryMappedViewStream CreateViewStream ()
331                 {
332                         return CreateViewStream (0, 0);//FIXME this is wrong
333                 }
334
335                 public MemoryMappedViewStream CreateViewStream (long offset, long size)
336                 {
337                         return CreateViewStream (offset, size, MemoryMappedFileAccess.ReadWrite);
338                 }
339
340                 public MemoryMappedViewStream CreateViewStream (long offset, long size, MemoryMappedFileAccess access)
341                 {
342                         var view = MemoryMappedView.Create (handle, offset, size, access);
343                         return new MemoryMappedViewStream (view);
344                 }
345
346                 public MemoryMappedViewAccessor CreateViewAccessor ()
347                 {
348                         return CreateViewAccessor (0, 0);
349                 }
350
351                 public MemoryMappedViewAccessor CreateViewAccessor (long offset, long size)
352                 {
353                         return CreateViewAccessor (offset, size, MemoryMappedFileAccess.ReadWrite);
354                 }
355
356                 public MemoryMappedViewAccessor CreateViewAccessor (long offset, long size, MemoryMappedFileAccess access)
357                 {
358                         var view = MemoryMappedView.Create (handle, offset, size, access);
359                         return new MemoryMappedViewAccessor (view);
360                 }
361
362                 MemoryMappedFile ()
363                 {
364                 }
365
366                 public void Dispose ()
367                 {
368                         Dispose (true);
369                 }
370
371                 protected virtual void Dispose (bool disposing)
372                 {
373                         if (disposing){
374                                 if (stream != null){
375                                         if (keepOpen == false)
376                                                 stream.Close ();
377                                         stream = null;
378                                 }
379                                 if (handle != IntPtr.Zero) {
380                                         MemoryMapImpl.CloseMapping (handle);
381                                         handle = IntPtr.Zero;
382                                 }
383                         }
384                 }
385
386                 [MonoTODO]
387                 public MemoryMappedFileSecurity GetAccessControl ()
388                 {
389                         throw new NotImplementedException ();
390                 }
391
392                 [MonoTODO]
393                 public void SetAccessControl (MemoryMappedFileSecurity memoryMappedFileSecurity)
394                 {
395                         throw new NotImplementedException ();
396                 }
397
398                 [MonoTODO]
399                 public SafeMemoryMappedFileHandle SafeMemoryMappedFileHandle {
400                         get {
401                                 throw new NotImplementedException ();
402                         }
403                 }
404
405                 // This converts a MemoryMappedFileAccess to a FileAccess. MemoryMappedViewStream and
406                 // MemoryMappedViewAccessor subclass UnmanagedMemoryStream and UnmanagedMemoryAccessor, which both use
407                 // FileAccess to determine whether they are writable and/or readable.
408                 internal static FileAccess GetFileAccess (MemoryMappedFileAccess access) {
409
410                         if (access == MemoryMappedFileAccess.Read) {
411                                 return FileAccess.Read;
412                         }
413                         if (access == MemoryMappedFileAccess.Write) {
414                                 return FileAccess.Write;
415                         }
416                         else if (access == MemoryMappedFileAccess.ReadWrite) {
417                                 return FileAccess.ReadWrite;
418                         }
419                         else if (access == MemoryMappedFileAccess.CopyOnWrite) {
420                                 return FileAccess.ReadWrite;
421                         }
422                         else if (access == MemoryMappedFileAccess.ReadExecute) {
423                                 return FileAccess.Read;
424                         }
425                         else if (access == MemoryMappedFileAccess.ReadWriteExecute) {
426                                 return FileAccess.ReadWrite;
427                         }
428
429                         // If we reached here, access was invalid.
430                         throw new ArgumentOutOfRangeException ("access");
431                 }
432         }
433 }
434