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.
33 using System
.Collections
.Generic
;
34 using Microsoft
.Win32
.SafeHandles
;
35 using Mono
.Unix
.Native
;
37 using System
.Runtime
.InteropServices
;
39 namespace System
.IO
.MemoryMappedFiles
41 public class MemoryMappedFile
: IDisposable
{
42 MemoryMappedFileAccess fileAccess
;
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
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
)
82 case FileMode
.CreateNew
:
83 return OpenFlags
.O_CREAT
| OpenFlags
.O_EXCL
;
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
;
95 return OpenFlags
.O_APPEND
;
103 // Turns the MemoryMappedFileAccess into the second half of open(2) flags
105 static OpenFlags
ToUnixMode (MemoryMappedFileAccess 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
:
119 return OpenFlags
.O_RDONLY
;
123 public static MemoryMappedFile
CreateFromFile (string path
, FileMode mode
, string mapName
, long capacity
, MemoryMappedFileAccess access
)
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");
133 if (MonoUtil
.IsUnix
){
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
);
144 UnixMarshal
.ThrowExceptionForLastError ();
146 throw new NotImplementedException ();
148 return new MemoryMappedFile () {
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
,
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");
182 ConfigureUnixFD (fileStream
.Handle
, inheritability
);
184 ConfigureWindowsFD (fileStream
.Handle
, inheritability
);
186 return new MemoryMappedFile () {
190 fileCapacity
= capacity
,
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
);
228 public static MemoryMappedFile
CreateOrOpen (string mapName
, long capacity
, MemoryMappedFileAccess access
, MemoryMappedFileOptions options
, MemoryMappedFileSecurity memoryMappedFileSecurity
, HandleInheritability handleInheritability
)
230 throw new NotImplementedException ();
234 public static MemoryMappedFile
OpenExisting (string mapName
)
236 throw new NotImplementedException ();
240 public static MemoryMappedFile
OpenExisting (string mapName
, MemoryMappedFileRights desiredAccessRights
)
242 throw new NotImplementedException ();
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
);
287 public void Dispose ()
292 protected virtual void Dispose (bool disposing
)
296 if (keepOpen
== false)
301 Syscall
.close (unix_fd
);
308 public MemoryMappedFileSecurity
GetAccessControl ()
310 throw new NotImplementedException ();
314 public void SetAccessControl (MemoryMappedFileSecurity memoryMappedFileSecurity
)
316 throw new NotImplementedException ();
320 public SafeMemoryMappedFileHandle SafeMemoryMappedFileHandle
{
322 throw new NotImplementedException ();
328 static MmapProts
ToUnixProts (MemoryMappedFileAccess access
)
333 case MemoryMappedFileAccess
.ReadWrite
:
334 return MmapProts
.PROT_WRITE
| MmapProts
.PROT_READ
;
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
:
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
)
358 pagesize
= Syscall
.getpagesize ();
361 Syscall
.fstat (file_handle
, out buf
);
362 long fsize
= buf
.st_size
;
364 if (size
== 0 || size
> fsize
)
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;