2010-06-21 Atsushi Enomoto <atsushi@ximian.com>
[mcs.git] / class / System.Core / System.IO.MemoryMappedFiles / MemoryMappedFile.cs
blob713d92d3b8bd0887c10648e05b61e8edbdde72a4
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:
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.
29 #if NET_4_0
31 using System;
32 using System.IO;
33 using System.Collections.Generic;
34 using Microsoft.Win32.SafeHandles;
35 using Mono.Unix.Native;
36 using Mono.Unix;
37 using System.Runtime.InteropServices;
39 namespace System.IO.MemoryMappedFiles
41 public class MemoryMappedFile : IDisposable {
42 MemoryMappedFileAccess fileAccess;
43 string name;
44 long fileCapacity;
47 // We allow the use of either the FileStream/keepOpen combo
48 // or a Unix file descriptor. This way we avoid the dependency on
49 // Mono's io-layer having the Unix file descriptors mapped to
50 // the same io-layer handle
52 FileStream stream;
53 bool keepOpen;
54 int unix_fd;
56 public static MemoryMappedFile CreateFromFile (string path)
58 return CreateFromFile (path, FileMode.Open, null, 0, MemoryMappedFileAccess.ReadWrite);
61 public static MemoryMappedFile CreateFromFile (string path, FileMode mode)
63 return CreateFromFile (path, mode, null, 0, MemoryMappedFileAccess.ReadWrite);
66 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName)
68 return CreateFromFile (path, mode, mapName, 0, MemoryMappedFileAccess.ReadWrite);
71 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName, long capacity)
73 return CreateFromFile (path, mode, mapName, capacity, MemoryMappedFileAccess.ReadWrite);
77 // Turns the FileMode into the first half of open(2) flags
79 static OpenFlags ToUnixMode (FileMode mode)
81 switch (mode){
82 case FileMode.CreateNew:
83 return OpenFlags.O_CREAT | OpenFlags.O_EXCL;
85 case FileMode.Create:
86 return OpenFlags.O_CREAT | OpenFlags.O_TRUNC;
88 case FileMode.OpenOrCreate:
89 return OpenFlags.O_CREAT;
91 case FileMode.Truncate:
92 return OpenFlags.O_TRUNC;
94 case FileMode.Append:
95 return OpenFlags.O_APPEND;
96 default:
97 case FileMode.Open:
98 return 0;
103 // Turns the MemoryMappedFileAccess into the second half of open(2) flags
105 static OpenFlags ToUnixMode (MemoryMappedFileAccess access)
107 switch (access){
108 case MemoryMappedFileAccess.CopyOnWrite:
109 case MemoryMappedFileAccess.ReadWriteExecute:
110 case MemoryMappedFileAccess.ReadWrite:
111 return OpenFlags.O_RDWR;
113 case MemoryMappedFileAccess.Write:
114 return OpenFlags.O_WRONLY;
116 case MemoryMappedFileAccess.ReadExecute:
117 case MemoryMappedFileAccess.Read:
118 default:
119 return OpenFlags.O_RDONLY;
123 public static MemoryMappedFile CreateFromFile (string path, FileMode mode, string mapName, long capacity, MemoryMappedFileAccess access)
125 if (path == null)
126 throw new ArgumentNullException ("path");
127 if (path.Length == 0)
128 throw new ArgumentException ("path");
129 if (mapName != null && mapName.Length == 0)
130 throw new ArgumentException ("mapName");
132 int fd;
133 if (MonoUtil.IsUnix){
134 Stat buf;
135 if (Syscall.stat (path, out buf) == -1)
136 UnixMarshal.ThrowExceptionForLastError ();
138 if ((capacity == 0 && buf.st_size == 0) || (capacity > buf.st_size))
139 throw new ArgumentException ("capacity");
141 fd = Syscall.open (path, ToUnixMode (mode) | ToUnixMode (access), FilePermissions.DEFFILEMODE);
143 if (fd == -1)
144 UnixMarshal.ThrowExceptionForLastError ();
145 } else
146 throw new NotImplementedException ();
148 return new MemoryMappedFile () {
149 unix_fd = fd,
150 fileAccess = access,
151 name = mapName,
152 fileCapacity = capacity
156 static void ConfigureUnixFD (IntPtr handle, HandleInheritability h)
158 // TODO: Mono.Posix is lacking O_CLOEXEC definitions for fcntl.
162 [DllImport("kernel32.dll", SetLastError = true)]
163 static extern bool SetHandleInformation (IntPtr hObject, int dwMask, int dwFlags);
164 static void ConfigureWindowsFD (IntPtr handle, HandleInheritability h)
166 SetHandleInformation (handle, 1 /* FLAG_INHERIT */, h == HandleInheritability.None ? 0 : 1);
169 [MonoLimitation ("memoryMappedFileSecurity is currently ignored")]
170 public static MemoryMappedFile CreateFromFile (FileStream fileStream, string mapName, long capacity, MemoryMappedFileAccess access,
171 MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability inheritability,
172 bool leaveOpen)
174 if (fileStream == null)
175 throw new ArgumentNullException ("fileStream");
176 if (mapName != null && mapName.Length == 0)
177 throw new ArgumentException ("mapName");
178 if ((capacity == 0 && fileStream.Length == 0) || (capacity > fileStream.Length))
179 throw new ArgumentException ("capacity");
181 if (MonoUtil.IsUnix)
182 ConfigureUnixFD (fileStream.Handle, inheritability);
183 else
184 ConfigureWindowsFD (fileStream.Handle, inheritability);
186 return new MemoryMappedFile () {
187 stream = fileStream,
188 fileAccess = access,
189 name = mapName,
190 fileCapacity = capacity,
191 keepOpen = leaveOpen
195 [MonoLimitation ("CreateNew requires that mapName be a file name on Unix")]
196 public static MemoryMappedFile CreateNew (string mapName, long capacity)
198 return CreateNew (mapName, capacity, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.DelayAllocatePages, null, 0);
201 [MonoLimitation ("CreateNew requires that mapName be a file name on Unix")]
202 public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access)
204 return CreateNew (mapName, capacity, access, MemoryMappedFileOptions.DelayAllocatePages, null, 0);
207 [MonoLimitation ("CreateNew requires that mapName be a file name on Unix; options and memoryMappedFileSecurity are ignored")]
208 public static MemoryMappedFile CreateNew (string mapName, long capacity, MemoryMappedFileAccess access,
209 MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity,
210 HandleInheritability handleInheritability)
212 return CreateFromFile (mapName, FileMode.CreateNew, mapName, capacity, access);
215 [MonoLimitation ("CreateOrOpen requires that mapName be a file name on Unix")]
216 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity)
218 return CreateOrOpen (mapName, capacity, MemoryMappedFileAccess.ReadWrite);
221 [MonoLimitation ("CreateOrOpen requires that mapName be a file name on Unix")]
222 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access)
224 return CreateFromFile (mapName, FileMode.OpenOrCreate, mapName, capacity, access);
227 [MonoTODO]
228 public static MemoryMappedFile CreateOrOpen (string mapName, long capacity, MemoryMappedFileAccess access, MemoryMappedFileOptions options, MemoryMappedFileSecurity memoryMappedFileSecurity, HandleInheritability handleInheritability)
230 throw new NotImplementedException ();
233 [MonoTODO]
234 public static MemoryMappedFile OpenExisting (string mapName)
236 throw new NotImplementedException ();
239 [MonoTODO]
240 public static MemoryMappedFile OpenExisting (string mapName, MemoryMappedFileRights desiredAccessRights)
242 throw new NotImplementedException ();
245 [MonoTODO]
246 public static MemoryMappedFile OpenExisting (string mapName, MemoryMappedFileRights desiredAccessRights, HandleInheritability inheritability)
248 throw new NotImplementedException ();
251 public MemoryMappedViewStream CreateViewStream ()
253 return CreateViewStream (0, 0);
256 public MemoryMappedViewStream CreateViewStream (long offset, long size)
258 return CreateViewStream (offset, size, MemoryMappedFileAccess.ReadWrite);
261 public MemoryMappedViewStream CreateViewStream (long offset, long size, MemoryMappedFileAccess access)
263 return new MemoryMappedViewStream (stream != null ? (int)stream.Handle : unix_fd, offset, size, access);
266 public MemoryMappedViewAccessor CreateViewAccessor ()
268 return CreateViewAccessor (0, 0);
271 public MemoryMappedViewAccessor CreateViewAccessor (long offset, long size)
273 return CreateViewAccessor (offset, size, MemoryMappedFileAccess.ReadWrite);
276 public MemoryMappedViewAccessor CreateViewAccessor (long offset, long size, MemoryMappedFileAccess access)
278 int file_handle = stream != null ? (int) stream.Handle : unix_fd;
280 return new MemoryMappedViewAccessor (file_handle, offset, size, access);
283 MemoryMappedFile ()
287 public void Dispose ()
289 Dispose (true);
292 protected virtual void Dispose (bool disposing)
294 if (disposing){
295 if (stream != null){
296 if (keepOpen == false)
297 stream.Close ();
298 unix_fd = -1;
300 if (unix_fd != -1)
301 Syscall.close (unix_fd);
302 unix_fd = -1;
303 stream = null;
307 [MonoTODO]
308 public MemoryMappedFileSecurity GetAccessControl ()
310 throw new NotImplementedException ();
313 [MonoTODO]
314 public void SetAccessControl (MemoryMappedFileSecurity memoryMappedFileSecurity)
316 throw new NotImplementedException ();
319 [MonoTODO]
320 public SafeMemoryMappedFileHandle SafeMemoryMappedFileHandle {
321 get {
322 throw new NotImplementedException ();
326 static int pagesize;
328 static MmapProts ToUnixProts (MemoryMappedFileAccess access)
330 MmapProts prots;
332 switch (access){
333 case MemoryMappedFileAccess.ReadWrite:
334 return MmapProts.PROT_WRITE | MmapProts.PROT_READ;
335 break;
337 case MemoryMappedFileAccess.Write:
338 return MmapProts.PROT_WRITE;
340 case MemoryMappedFileAccess.CopyOnWrite:
341 return MmapProts.PROT_WRITE | MmapProts.PROT_READ;
343 case MemoryMappedFileAccess.ReadExecute:
344 return MmapProts.PROT_EXEC;
346 case MemoryMappedFileAccess.ReadWriteExecute:
347 return MmapProts.PROT_WRITE | MmapProts.PROT_READ | MmapProts.PROT_EXEC;
349 case MemoryMappedFileAccess.Read:
350 default:
351 return MmapProts.PROT_READ;
355 internal static unsafe void MapPosix (int file_handle, long offset, ref long size, MemoryMappedFileAccess access, out IntPtr map_addr, out int offset_diff)
357 if (pagesize == 0)
358 pagesize = Syscall.getpagesize ();
360 Stat buf;
361 Syscall.fstat (file_handle, out buf);
362 long fsize = buf.st_size;
364 if (size == 0 || size > fsize)
365 size = fsize;
367 // Align offset
368 long real_offset = offset & ~(pagesize - 1);
370 offset_diff = (int)(offset - real_offset);
372 // FIXME: Need to determine the unix fd for the file, Handle is only
373 // equal to it by accident
375 // The new API no longer uses FileStream everywhere, but exposes instead
376 // the filename (with one exception), we could move this API to use
377 // file descriptors instead of the FileStream plus its Handle.
379 map_addr = Syscall.mmap (IntPtr.Zero, (ulong) size,
380 ToUnixProts (access),
381 access == MemoryMappedFileAccess.CopyOnWrite ? MmapFlags.MAP_PRIVATE : MmapFlags.MAP_SHARED,
382 file_handle, real_offset);
384 if (map_addr == (IntPtr)(-1))
385 throw new IOException ("mmap failed for fd#" + file_handle + "(" + offset + ", " + size + ")");
388 internal static bool UnmapPosix (IntPtr map_addr, ulong map_size)
390 return Syscall.munmap (map_addr, map_size) == 0;
396 #endif