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 ("capacity", "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 UnauthorizedAccessException ("Access to the path is denied.");
91 return new ArgumentOutOfRangeException ("capacity", "The capacity cannot be greater than the size of the system's logical address space.");
93 return new IOException ("Failed with unknown error code " + error);
97 internal static IntPtr OpenFile (string path, FileMode mode, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options)
100 IntPtr res = OpenFileInternal (path, mode, mapName, out capacity, access, options, out error);
102 throw CreateException (error, path);
106 internal static IntPtr OpenHandle (IntPtr handle, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options)
109 IntPtr res = OpenHandleInternal (handle, mapName, out capacity, access, options, out error);
111 throw CreateException (error, "<none>");
117 public class MemoryMappedFile : IDisposable {
118 // MemoryMappedFileAccess fileAccess;
120 // long fileCapacity;
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
132 public static MemoryMappedFile CreateFromFile (string path)
134 return CreateFromFile (path, FileMode.Open, null, 0, MemoryMappedFileAccess.ReadWrite);
137 public static MemoryMappedFile CreateFromFile (string path, FileMode mode)
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");
147 IntPtr handle = MemoryMapImpl.OpenFile (path, mode, null, out capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None);
149 return new MemoryMappedFile () {
151 // fileAccess = MemoryMappedFileAccess.ReadWrite,
152 // fileCapacity = capacity
156 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName)
158 return CreateFromFile (path, mode, mapName, 0, MemoryMappedFileAccess.ReadWrite);
161 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName, long capacity)
163 return CreateFromFile (path, mode, mapName, capacity, MemoryMappedFileAccess.ReadWrite);
166 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName, long capacity, MemoryMappedFileAccess access)
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");
177 throw new ArgumentOutOfRangeException ("capacity");
179 IntPtr handle = MemoryMapImpl.OpenFile (path, mode, mapName, out capacity, access, MemoryMappedFileOptions.None);
181 return new MemoryMappedFile () {
183 // fileAccess = access,
185 // fileCapacity = capacity
189 public static MemoryMappedFile CreateFromFile (FileStream fileStream, string mapName, long capacity, MemoryMappedFileAccess access,
190 HandleInheritability inheritability,
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");
200 IntPtr handle = MemoryMapImpl.OpenHandle (fileStream.SafeFileHandle.DangerousGetHandle (), mapName, out capacity, access, MemoryMappedFileOptions.None);
202 MemoryMapImpl.ConfigureHandleInheritability (handle, inheritability);
204 return new MemoryMappedFile () {
206 // fileAccess = access,
208 // fileCapacity = capacity,
215 [MonoLimitation ("memoryMappedFileSecurity is currently ignored")]
216 public static MemoryMappedFile CreateFromFile (FileStream fileStream, string mapName, long capacity, MemoryMappedFileAccess access,
217 MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability inheritability,
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");
227 IntPtr handle = MemoryMapImpl.OpenHandle (fileStream.SafeFileHandle.DangerousGetHandle (), mapName, out capacity, access, MemoryMappedFileOptions.None);
229 MemoryMapImpl.ConfigureHandleInheritability (handle, inheritability);
231 return new MemoryMappedFile () {
233 // fileAccess = access,
235 // fileCapacity = capacity,
243 static MemoryMappedFile CoreShmCreate (string mapName, long capacity, MemoryMappedFileAccess access,
244 MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity,
245 HandleInheritability inheritability, FileMode mode)
247 if (mapName != null && mapName.Length == 0)
248 throw new ArgumentException ("mapName");
250 throw new ArgumentOutOfRangeException ("capacity");
252 IntPtr handle = MemoryMapImpl.OpenFile (null, mode, mapName, out capacity, access, options);
254 return new MemoryMappedFile () {
256 // fileAccess = access,
258 // fileCapacity = capacity
262 [MonoLimitation ("Named mappings scope is process local")]
263 public static MemoryMappedFile CreateNew (string mapName, long capacity)
265 return CreateNew (mapName, capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, null, HandleInheritability.None);
268 [MonoLimitation ("Named mappings scope is process local")]
269 public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access)
271 return CreateNew (mapName, capacity, access, MemoryMappedFileOptions.None, null, HandleInheritability.None);
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)
277 return CreateNew (mapName, capacity, access, options, null, inheritability);
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)
285 return CoreShmCreate (mapName, capacity, access, options, memoryMappedFileSecurity, inheritability, FileMode.CreateNew);
288 [MonoLimitation ("Named mappings scope is process local")]
289 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity)
291 return CreateOrOpen (mapName, capacity, MemoryMappedFileAccess.ReadWrite);
294 [MonoLimitation ("Named mappings scope is process local")]
295 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access)
297 return CreateOrOpen (mapName, capacity, access, MemoryMappedFileOptions.None, null, HandleInheritability.None);
300 [MonoLimitation ("Named mappings scope is process local")]
301 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, HandleInheritability inheritability)
303 return CreateOrOpen (mapName, capacity, access, options, null, inheritability);
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)
309 return CoreShmCreate (mapName, capacity, access, options, memoryMappedFileSecurity, inheritability, FileMode.OpenOrCreate);
312 [MonoLimitation ("Named mappings scope is process local")]
313 public static MemoryMappedFile OpenExisting (string mapName)
315 throw new NotImplementedException ();
318 [MonoLimitation ("Named mappings scope is process local")]
319 public static MemoryMappedFile OpenExisting (string mapName, MemoryMappedFileRights desiredAccessRights)
321 throw new NotImplementedException ();
324 [MonoLimitation ("Named mappings scope is process local")]
325 public static MemoryMappedFile OpenExisting (string mapName, MemoryMappedFileRights desiredAccessRights, HandleInheritability inheritability)
327 throw new NotImplementedException ();
330 public MemoryMappedViewStream CreateViewStream ()
332 return CreateViewStream (0, 0);//FIXME this is wrong
335 public MemoryMappedViewStream CreateViewStream (long offset, long size)
337 return CreateViewStream (offset, size, MemoryMappedFileAccess.ReadWrite);
340 public MemoryMappedViewStream CreateViewStream (long offset, long size, MemoryMappedFileAccess access)
342 var view = MemoryMappedView.Create (handle, offset, size, access);
343 return new MemoryMappedViewStream (view);
346 public MemoryMappedViewAccessor CreateViewAccessor ()
348 return CreateViewAccessor (0, 0);
351 public MemoryMappedViewAccessor CreateViewAccessor (long offset, long size)
353 return CreateViewAccessor (offset, size, MemoryMappedFileAccess.ReadWrite);
356 public MemoryMappedViewAccessor CreateViewAccessor (long offset, long size, MemoryMappedFileAccess access)
358 var view = MemoryMappedView.Create (handle, offset, size, access);
359 return new MemoryMappedViewAccessor (view);
366 public void Dispose ()
371 protected virtual void Dispose (bool disposing)
375 if (keepOpen == false)
379 if (handle != IntPtr.Zero) {
380 MemoryMapImpl.CloseMapping (handle);
381 handle = IntPtr.Zero;
387 public MemoryMappedFileSecurity GetAccessControl ()
389 throw new NotImplementedException ();
393 public void SetAccessControl (MemoryMappedFileSecurity memoryMappedFileSecurity)
395 throw new NotImplementedException ();
399 public SafeMemoryMappedFileHandle SafeMemoryMappedFileHandle {
401 throw new NotImplementedException ();
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) {
410 if (access == MemoryMappedFileAccess.Read) {
411 return FileAccess.Read;
413 if (access == MemoryMappedFileAccess.Write) {
414 return FileAccess.Write;
416 else if (access == MemoryMappedFileAccess.ReadWrite) {
417 return FileAccess.ReadWrite;
419 else if (access == MemoryMappedFileAccess.CopyOnWrite) {
420 return FileAccess.ReadWrite;
422 else if (access == MemoryMappedFileAccess.ReadExecute) {
423 return FileAccess.Read;
425 else if (access == MemoryMappedFileAccess.ReadWriteExecute) {
426 return FileAccess.ReadWrite;
429 // If we reached here, access was invalid.
430 throw new ArgumentOutOfRangeException ("access");