5 // Zoltan Varga (vargaz@gmail.com)
7 // Copyright (C) 2009, Novell, Inc (http://www.novell.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
31 using System.Collections.Generic;
32 using Microsoft.Win32.SafeHandles;
33 using System.Runtime.InteropServices;
34 using System.Runtime.CompilerServices;
37 namespace System.IO.MemoryMappedFiles
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);
43 [MethodImplAttribute (MethodImplOptions.InternalCall)]
44 static extern IntPtr OpenHandleInternal (IntPtr handle, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, out int error);
46 [MethodImplAttribute (MethodImplOptions.InternalCall)]
47 internal extern static void CloseMapping (IntPtr handle);
49 [MethodImplAttribute (MethodImplOptions.InternalCall)]
50 internal extern static void Flush (IntPtr file_handle);
52 [MethodImplAttribute (MethodImplOptions.InternalCall)]
53 internal extern static void ConfigureHandleInheritability (IntPtr handle, HandleInheritability inheritability);
55 [MethodImplAttribute (MethodImplOptions.InternalCall)]
56 internal extern static bool Unmap (IntPtr mmap_handle);
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);
61 internal static void Map (IntPtr handle, long offset, ref long size, MemoryMappedFileAccess access, out IntPtr mmap_handle, out IntPtr base_address)
63 int error = MapInternal (handle, offset, ref size, access, out mmap_handle, out base_address);
65 throw CreateException (error, "<none>");
68 static Exception CreateException (int error, string path) {
71 return new ArgumentException ("A positive capacity must be specified for a Memory Mapped File backed by an empty file.");
73 return new ArgumentOutOfRangeException ("The capacity may not be smaller than the file size.");
75 return new FileNotFoundException (path);
77 return new IOException ("The file already exists");
79 return new PathTooLongException ();
81 return new IOException ("Could not open file");
83 return new ArgumentException ("Capacity must be bigger than zero for non-file mappings");
85 return new ArgumentException ("Invalid FileMode value.");
87 return new IOException ("Could not map file");
89 return new IOException ("Failed with unknown error code " + error);
93 internal static IntPtr OpenFile (string path, FileMode mode, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options)
96 IntPtr res = OpenFileInternal (path, mode, mapName, out capacity, access, options, out error);
98 throw CreateException (error, path);
102 internal static IntPtr OpenHandle (IntPtr handle, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options)
105 IntPtr res = OpenHandleInternal (handle, mapName, out capacity, access, options, out error);
107 throw CreateException (error, "<none>");
113 public class MemoryMappedFile : IDisposable {
114 // MemoryMappedFileAccess fileAccess;
116 // long fileCapacity;
119 // We allow the use of either the FileStream/keepOpen combo
120 // or a Unix file descriptor. This way we avoid the dependency on
121 // Mono's io-layer having the Unix file descriptors mapped to
122 // the same io-layer handle
128 public static MemoryMappedFile CreateFromFile (string path)
130 return CreateFromFile (path, FileMode.Open, null, 0, MemoryMappedFileAccess.ReadWrite);
133 public static MemoryMappedFile CreateFromFile (string path, FileMode mode)
137 throw new ArgumentNullException ("path");
138 if (path.Length == 0)
139 throw new ArgumentException ("path");
140 if (mode == FileMode.Append)
141 throw new ArgumentException ("mode");
143 IntPtr handle = MemoryMapImpl.OpenFile (path, mode, null, out capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.DelayAllocatePages);
145 return new MemoryMappedFile () {
147 // fileAccess = MemoryMappedFileAccess.ReadWrite,
148 // fileCapacity = capacity
152 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName)
154 return CreateFromFile (path, mode, mapName, 0, MemoryMappedFileAccess.ReadWrite);
157 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName, long capacity)
159 return CreateFromFile (path, mode, mapName, capacity, MemoryMappedFileAccess.ReadWrite);
162 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName, long capacity, MemoryMappedFileAccess access)
165 throw new ArgumentNullException ("path");
166 if (path.Length == 0)
167 throw new ArgumentException ("path");
168 if (mapName != null && mapName.Length == 0)
169 throw new ArgumentException ("mapName");
170 if (mode == FileMode.Append)
171 throw new ArgumentException ("mode");
173 throw new ArgumentOutOfRangeException ("capacity");
175 IntPtr handle = MemoryMapImpl.OpenFile (path, mode, mapName, out capacity, access, MemoryMappedFileOptions.DelayAllocatePages);
177 return new MemoryMappedFile () {
179 // fileAccess = access,
181 // fileCapacity = capacity
185 public static MemoryMappedFile CreateFromFile (FileStream fileStream, string mapName, long capacity, MemoryMappedFileAccess access,
186 HandleInheritability inheritability,
189 if (fileStream == null)
190 throw new ArgumentNullException ("fileStream");
191 if (mapName != null && mapName.Length == 0)
192 throw new ArgumentException ("mapName");
193 if ((!MonoUtil.IsUnix && capacity == 0 && fileStream.Length == 0) || (capacity > fileStream.Length))
194 throw new ArgumentException ("capacity");
196 IntPtr handle = MemoryMapImpl.OpenHandle (fileStream.SafeFileHandle.DangerousGetHandle (), mapName, out capacity, access, MemoryMappedFileOptions.DelayAllocatePages);
198 MemoryMapImpl.ConfigureHandleInheritability (handle, inheritability);
200 return new MemoryMappedFile () {
202 // fileAccess = access,
204 // fileCapacity = capacity,
211 [MonoLimitation ("memoryMappedFileSecurity is currently ignored")]
212 public static MemoryMappedFile CreateFromFile (FileStream fileStream, string mapName, long capacity, MemoryMappedFileAccess access,
213 MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability inheritability,
216 if (fileStream == null)
217 throw new ArgumentNullException ("fileStream");
218 if (mapName != null && mapName.Length == 0)
219 throw new ArgumentException ("mapName");
220 if ((!MonoUtil.IsUnix && capacity == 0 && fileStream.Length == 0) || (capacity > fileStream.Length))
221 throw new ArgumentException ("capacity");
223 IntPtr handle = MemoryMapImpl.OpenHandle (fileStream.SafeFileHandle.DangerousGetHandle (), mapName, out capacity, access, MemoryMappedFileOptions.DelayAllocatePages);
225 MemoryMapImpl.ConfigureHandleInheritability (handle, inheritability);
227 return new MemoryMappedFile () {
229 // fileAccess = access,
231 // fileCapacity = capacity,
239 static MemoryMappedFile CoreShmCreate (string mapName, long capacity, MemoryMappedFileAccess access,
240 MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity,
241 HandleInheritability inheritability, FileMode mode)
243 if (mapName != null && mapName.Length == 0)
244 throw new ArgumentException ("mapName");
246 throw new ArgumentOutOfRangeException ("capacity");
248 IntPtr handle = MemoryMapImpl.OpenFile (null, mode, mapName, out capacity, access, options);
250 return new MemoryMappedFile () {
252 // fileAccess = access,
254 // fileCapacity = capacity
258 [MonoLimitation ("Named mappings scope is process local")]
259 public static MemoryMappedFile CreateNew (string mapName, long capacity)
261 return CreateNew (mapName, capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.DelayAllocatePages, null, HandleInheritability.None);
264 [MonoLimitation ("Named mappings scope is process local")]
265 public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access)
267 return CreateNew (mapName, capacity, access, MemoryMappedFileOptions.DelayAllocatePages, null, HandleInheritability.None);
270 [MonoLimitation ("Named mappings scope is process local; options is ignored")]
271 public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, HandleInheritability inheritability)
273 return CreateNew (mapName, capacity, access, options, null, inheritability);
276 [MonoLimitation ("Named mappings scope is process local; options and memoryMappedFileSecurity are ignored")]
277 public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access,
278 MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity,
279 HandleInheritability inheritability)
281 return CoreShmCreate (mapName, capacity, access, options, memoryMappedFileSecurity, inheritability, FileMode.CreateNew);
284 [MonoLimitation ("Named mappings scope is process local")]
285 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity)
287 return CreateOrOpen (mapName, capacity, MemoryMappedFileAccess.ReadWrite);
290 [MonoLimitation ("Named mappings scope is process local")]
291 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access)
293 return CreateOrOpen (mapName, capacity, access, MemoryMappedFileOptions.DelayAllocatePages, null, HandleInheritability.None);
296 [MonoLimitation ("Named mappings scope is process local")]
297 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, HandleInheritability inheritability)
299 return CreateOrOpen (mapName, capacity, access, options, null, inheritability);
302 [MonoLimitation ("Named mappings scope is process local")]
303 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability inheritability)
305 return CoreShmCreate (mapName, capacity, access, options, memoryMappedFileSecurity, inheritability, FileMode.OpenOrCreate);
308 [MonoLimitation ("Named mappings scope is process local")]
309 public static MemoryMappedFile OpenExisting (string mapName)
311 throw new NotImplementedException ();
314 [MonoLimitation ("Named mappings scope is process local")]
315 public static MemoryMappedFile OpenExisting (string mapName, MemoryMappedFileRights desiredAccessRights)
317 throw new NotImplementedException ();
320 [MonoLimitation ("Named mappings scope is process local")]
321 public static MemoryMappedFile OpenExisting (string mapName, MemoryMappedFileRights desiredAccessRights, HandleInheritability inheritability)
323 throw new NotImplementedException ();
326 public MemoryMappedViewStream CreateViewStream ()
328 return CreateViewStream (0, 0);//FIXME this is wrong
331 public MemoryMappedViewStream CreateViewStream (long offset, long size)
333 return CreateViewStream (offset, size, MemoryMappedFileAccess.ReadWrite);
336 public MemoryMappedViewStream CreateViewStream (long offset, long size, MemoryMappedFileAccess access)
338 var view = MemoryMappedView.Create (handle, offset, size, access);
339 return new MemoryMappedViewStream (view);
342 public MemoryMappedViewAccessor CreateViewAccessor ()
344 return CreateViewAccessor (0, 0);
347 public MemoryMappedViewAccessor CreateViewAccessor (long offset, long size)
349 return CreateViewAccessor (offset, size, MemoryMappedFileAccess.ReadWrite);
352 public MemoryMappedViewAccessor CreateViewAccessor (long offset, long size, MemoryMappedFileAccess access)
354 var view = MemoryMappedView.Create (handle, offset, size, access);
355 return new MemoryMappedViewAccessor (view);
362 public void Dispose ()
367 protected virtual void Dispose (bool disposing)
371 if (keepOpen == false)
375 if (handle != IntPtr.Zero) {
376 MemoryMapImpl.CloseMapping (handle);
377 handle = IntPtr.Zero;
383 public MemoryMappedFileSecurity GetAccessControl ()
385 throw new NotImplementedException ();
389 public void SetAccessControl (MemoryMappedFileSecurity memoryMappedFileSecurity)
391 throw new NotImplementedException ();
395 public SafeMemoryMappedFileHandle SafeMemoryMappedFileHandle {
397 throw new NotImplementedException ();
401 // This converts a MemoryMappedFileAccess to a FileAccess. MemoryMappedViewStream and
402 // MemoryMappedViewAccessor subclass UnmanagedMemoryStream and UnmanagedMemoryAccessor, which both use
403 // FileAccess to determine whether they are writable and/or readable.
404 internal static FileAccess GetFileAccess (MemoryMappedFileAccess access) {
406 if (access == MemoryMappedFileAccess.Read) {
407 return FileAccess.Read;
409 if (access == MemoryMappedFileAccess.Write) {
410 return FileAccess.Write;
412 else if (access == MemoryMappedFileAccess.ReadWrite) {
413 return FileAccess.ReadWrite;
415 else if (access == MemoryMappedFileAccess.CopyOnWrite) {
416 return FileAccess.ReadWrite;
418 else if (access == MemoryMappedFileAccess.ReadExecute) {
419 return FileAccess.Read;
421 else if (access == MemoryMappedFileAccess.ReadWriteExecute) {
422 return FileAccess.ReadWrite;
425 // If we reached here, access was invalid.
426 throw new ArgumentOutOfRangeException ("access");