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;
36 namespace System.IO.MemoryMappedFiles
38 internal static class MemoryMapImpl {
39 [MethodImplAttribute (MethodImplOptions.InternalCall)]
40 static extern IntPtr OpenFileInternal (string path, FileMode mode, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, out int error);
42 [MethodImplAttribute (MethodImplOptions.InternalCall)]
43 static extern IntPtr OpenHandleInternal (IntPtr handle, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, out int error);
45 [MethodImplAttribute (MethodImplOptions.InternalCall)]
46 internal extern static void CloseMapping (IntPtr handle);
48 [MethodImplAttribute (MethodImplOptions.InternalCall)]
49 internal extern static void Flush (IntPtr file_handle);
51 [MethodImplAttribute (MethodImplOptions.InternalCall)]
52 internal extern static void ConfigureHandleInheritability (IntPtr handle, HandleInheritability inheritability);
54 [MethodImplAttribute (MethodImplOptions.InternalCall)]
55 internal extern static bool Unmap (IntPtr mmap_handle);
57 [MethodImplAttribute (MethodImplOptions.InternalCall)]
58 extern static int MapInternal (IntPtr handle, long offset, ref long size, MemoryMappedFileAccess access, out IntPtr mmap_handle, out IntPtr base_address);
60 internal static void Map (IntPtr handle, long offset, ref long size, MemoryMappedFileAccess access, out IntPtr mmap_handle, out IntPtr base_address)
62 int error = MapInternal (handle, offset, ref size, access, out mmap_handle, out base_address);
64 throw CreateException (error, "<none>");
67 static Exception CreateException (int error, string path) {
70 return new ArgumentException ("A positive capacity must be specified for a Memory Mapped File backed by an empty file.");
72 return new ArgumentOutOfRangeException ("capacity", "The capacity may not be smaller than the file size.");
74 return new FileNotFoundException (path);
76 return new IOException ("The file already exists");
78 return new PathTooLongException ();
80 return new IOException ("Could not open file");
82 return new ArgumentException ("Capacity must be bigger than zero for non-file mappings");
84 return new ArgumentException ("Invalid FileMode value.");
86 return new IOException ("Could not map file");
88 return new UnauthorizedAccessException ("Access to the path is denied.");
90 return new ArgumentOutOfRangeException ("capacity", "The capacity cannot be greater than the size of the system's logical address space.");
92 return new IOException ("Failed with unknown error code " + error);
96 internal static IntPtr OpenFile (string path, FileMode mode, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options)
99 IntPtr res = OpenFileInternal (path, mode, mapName, out capacity, access, options, out error);
101 throw CreateException (error, path);
105 internal static IntPtr OpenHandle (IntPtr handle, string mapName, out long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options)
108 IntPtr res = OpenHandleInternal (handle, mapName, out capacity, access, options, out error);
110 throw CreateException (error, "<none>");
115 public class MemoryMappedFile : IDisposable {
116 // MemoryMappedFileAccess fileAccess;
118 // long fileCapacity;
121 // We allow the use of either the FileStream/keepOpen combo
122 // or a Unix file descriptor. This way we avoid the dependency on
123 // Mono's io-layer having the Unix file descriptors mapped to
124 // the same io-layer handle
128 SafeMemoryMappedFileHandle handle;
130 public static MemoryMappedFile CreateFromFile (string path)
132 return CreateFromFile (path, FileMode.Open, null, 0, MemoryMappedFileAccess.ReadWrite);
135 public static MemoryMappedFile CreateFromFile (string path, FileMode mode)
139 throw new ArgumentNullException ("path");
140 if (path.Length == 0)
141 throw new ArgumentException ("path");
142 if (mode == FileMode.Append)
143 throw new ArgumentException ("mode");
145 IntPtr handle = MemoryMapImpl.OpenFile (path, mode, null, out capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None);
147 return new MemoryMappedFile () {
148 handle = new SafeMemoryMappedFileHandle (handle, true),
149 // fileAccess = MemoryMappedFileAccess.ReadWrite,
150 // fileCapacity = capacity
154 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName)
156 return CreateFromFile (path, mode, mapName, 0, MemoryMappedFileAccess.ReadWrite);
159 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName, long capacity)
161 return CreateFromFile (path, mode, mapName, capacity, MemoryMappedFileAccess.ReadWrite);
164 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName, long capacity, MemoryMappedFileAccess access)
167 throw new ArgumentNullException ("path");
168 if (path.Length == 0)
169 throw new ArgumentException ("path");
170 if (mapName != null && mapName.Length == 0)
171 throw new ArgumentException ("mapName");
172 if (mode == FileMode.Append)
173 throw new ArgumentException ("mode");
175 throw new ArgumentOutOfRangeException ("capacity");
177 IntPtr handle = MemoryMapImpl.OpenFile (path, mode, mapName, out capacity, access, MemoryMappedFileOptions.None);
179 return new MemoryMappedFile () {
180 handle = new SafeMemoryMappedFileHandle (handle, true),
181 // fileAccess = access,
183 // fileCapacity = capacity
187 public static MemoryMappedFile CreateFromFile (FileStream fileStream, string mapName, long capacity, MemoryMappedFileAccess access,
188 HandleInheritability inheritability,
191 if (fileStream == null)
192 throw new ArgumentNullException ("fileStream");
193 if (mapName != null && mapName.Length == 0)
194 throw new ArgumentException ("mapName");
195 if ((!MonoUtil.IsUnix && capacity == 0 && fileStream.Length == 0) || (capacity > fileStream.Length))
196 throw new ArgumentException ("capacity");
198 IntPtr handle = MemoryMapImpl.OpenHandle (fileStream.SafeFileHandle.DangerousGetHandle (), mapName, out capacity, access, MemoryMappedFileOptions.None);
200 MemoryMapImpl.ConfigureHandleInheritability (handle, inheritability);
202 return new MemoryMappedFile () {
203 handle = new SafeMemoryMappedFileHandle (handle, true),
204 // fileAccess = access,
206 // fileCapacity = capacity,
213 [MonoLimitation ("memoryMappedFileSecurity is currently ignored")]
214 public static MemoryMappedFile CreateFromFile (FileStream fileStream, string mapName, long capacity, MemoryMappedFileAccess access,
215 MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability inheritability,
218 if (fileStream == null)
219 throw new ArgumentNullException ("fileStream");
220 if (mapName != null && mapName.Length == 0)
221 throw new ArgumentException ("mapName");
222 if ((!MonoUtil.IsUnix && capacity == 0 && fileStream.Length == 0) || (capacity > fileStream.Length))
223 throw new ArgumentException ("capacity");
225 IntPtr handle = MemoryMapImpl.OpenHandle (fileStream.SafeFileHandle.DangerousGetHandle (), mapName, out capacity, access, MemoryMappedFileOptions.None);
227 MemoryMapImpl.ConfigureHandleInheritability (handle, inheritability);
229 return new MemoryMappedFile () {
230 handle = new SafeMemoryMappedFileHandle (handle, true),
231 // fileAccess = access,
233 // fileCapacity = capacity,
241 static MemoryMappedFile CoreShmCreate (string mapName, long capacity, MemoryMappedFileAccess access,
242 MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity,
243 HandleInheritability inheritability, FileMode mode)
245 if (mapName != null && mapName.Length == 0)
246 throw new ArgumentException ("mapName");
248 throw new ArgumentOutOfRangeException ("capacity");
250 IntPtr handle = MemoryMapImpl.OpenFile (null, mode, mapName, out capacity, access, options);
252 return new MemoryMappedFile () {
253 handle = new SafeMemoryMappedFileHandle (handle, true),
254 // fileAccess = access,
256 // fileCapacity = capacity
260 [MonoLimitation ("Named mappings scope is process local")]
261 public static MemoryMappedFile CreateNew (string mapName, long capacity)
263 return CreateNew (mapName, capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, null, HandleInheritability.None);
266 [MonoLimitation ("Named mappings scope is process local")]
267 public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access)
269 return CreateNew (mapName, capacity, access, MemoryMappedFileOptions.None, null, HandleInheritability.None);
272 [MonoLimitation ("Named mappings scope is process local; options is ignored")]
273 public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, HandleInheritability inheritability)
275 return CreateNew (mapName, capacity, access, options, null, inheritability);
278 [MonoLimitation ("Named mappings scope is process local; options and memoryMappedFileSecurity are ignored")]
279 public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access,
280 MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity,
281 HandleInheritability inheritability)
283 return CoreShmCreate (mapName, capacity, access, options, memoryMappedFileSecurity, inheritability, FileMode.CreateNew);
286 [MonoLimitation ("Named mappings scope is process local")]
287 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity)
289 return CreateOrOpen (mapName, capacity, MemoryMappedFileAccess.ReadWrite);
292 [MonoLimitation ("Named mappings scope is process local")]
293 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access)
295 return CreateOrOpen (mapName, capacity, access, MemoryMappedFileOptions.None, null, HandleInheritability.None);
298 [MonoLimitation ("Named mappings scope is process local")]
299 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, HandleInheritability inheritability)
301 return CreateOrOpen (mapName, capacity, access, options, null, inheritability);
304 [MonoLimitation ("Named mappings scope is process local")]
305 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability inheritability)
307 return CoreShmCreate (mapName, capacity, access, options, memoryMappedFileSecurity, inheritability, FileMode.OpenOrCreate);
310 [MonoLimitation ("Named mappings scope is process local")]
311 public static MemoryMappedFile OpenExisting (string mapName)
313 throw new NotImplementedException ();
316 [MonoLimitation ("Named mappings scope is process local")]
317 public static MemoryMappedFile OpenExisting (string mapName, MemoryMappedFileRights desiredAccessRights)
319 throw new NotImplementedException ();
322 [MonoLimitation ("Named mappings scope is process local")]
323 public static MemoryMappedFile OpenExisting (string mapName, MemoryMappedFileRights desiredAccessRights, HandleInheritability inheritability)
325 throw new NotImplementedException ();
328 public MemoryMappedViewStream CreateViewStream ()
330 return CreateViewStream (0, 0);//FIXME this is wrong
333 public MemoryMappedViewStream CreateViewStream (long offset, long size)
335 return CreateViewStream (offset, size, MemoryMappedFileAccess.ReadWrite);
338 public MemoryMappedViewStream CreateViewStream (long offset, long size, MemoryMappedFileAccess access)
340 var view = MemoryMappedView.Create (handle.DangerousGetHandle (), offset, size, access);
341 return new MemoryMappedViewStream (view);
344 public MemoryMappedViewAccessor CreateViewAccessor ()
346 return CreateViewAccessor (0, 0);
349 public MemoryMappedViewAccessor CreateViewAccessor (long offset, long size)
351 return CreateViewAccessor (offset, size, MemoryMappedFileAccess.ReadWrite);
354 public MemoryMappedViewAccessor CreateViewAccessor (long offset, long size, MemoryMappedFileAccess access)
356 var view = MemoryMappedView.Create (handle.DangerousGetHandle (), offset, size, access);
357 return new MemoryMappedViewAccessor (view);
364 public void Dispose ()
369 protected virtual void Dispose (bool disposing)
372 if (stream != null) {
373 if (keepOpen == false)
378 if (handle != null) {
385 public MemoryMappedFileSecurity GetAccessControl ()
387 throw new NotImplementedException ();
391 public void SetAccessControl (MemoryMappedFileSecurity memoryMappedFileSecurity)
393 throw new NotImplementedException ();
397 public SafeMemoryMappedFileHandle SafeMemoryMappedFileHandle {
399 throw new NotImplementedException ();
403 // This converts a MemoryMappedFileAccess to a FileAccess. MemoryMappedViewStream and
404 // MemoryMappedViewAccessor subclass UnmanagedMemoryStream and UnmanagedMemoryAccessor, which both use
405 // FileAccess to determine whether they are writable and/or readable.
406 internal static FileAccess GetFileAccess (MemoryMappedFileAccess access) {
408 if (access == MemoryMappedFileAccess.Read) {
409 return FileAccess.Read;
411 if (access == MemoryMappedFileAccess.Write) {
412 return FileAccess.Write;
414 else if (access == MemoryMappedFileAccess.ReadWrite) {
415 return FileAccess.ReadWrite;
417 else if (access == MemoryMappedFileAccess.CopyOnWrite) {
418 return FileAccess.ReadWrite;
420 else if (access == MemoryMappedFileAccess.ReadExecute) {
421 return FileAccess.Read;
423 else if (access == MemoryMappedFileAccess.ReadWriteExecute) {
424 return FileAccess.ReadWrite;
427 // If we reached here, access was invalid.
428 throw new ArgumentOutOfRangeException ("access");