Beispiel #1
0
 public unsafe static extern void *MapViewOfFile(SafeMemoryMappedFileHandle hMap, uint access, uint offsetHigh, uint ofsfetLow, IntPtr size);
Beispiel #2
0
        public static MemoryMappedFile CreateFromFile(FileStream fileStream, string?mapName, long capacity,
                                                      MemoryMappedFileAccess access,
                                                      HandleInheritability inheritability, bool leaveOpen)
        {
            if (fileStream == null)
            {
                throw new ArgumentNullException(nameof(fileStream), SR.ArgumentNull_FileStream);
            }

            if (mapName != null && mapName.Length == 0)
            {
                throw new ArgumentException(SR.Argument_MapNameEmptyString);
            }

            if (capacity < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_PositiveOrDefaultCapacityRequired);
            }

            if (capacity == 0 && fileStream.Length == 0)
            {
                throw new ArgumentException(SR.Argument_EmptyFile);
            }

            if (access < MemoryMappedFileAccess.ReadWrite ||
                access > MemoryMappedFileAccess.ReadWriteExecute)
            {
                throw new ArgumentOutOfRangeException(nameof(access));
            }

            if (access == MemoryMappedFileAccess.Write)
            {
                throw new ArgumentException(SR.Argument_NewMMFWriteAccessNotAllowed, nameof(access));
            }

            if (access == MemoryMappedFileAccess.Read && capacity > fileStream.Length)
            {
                throw new ArgumentException(SR.Argument_ReadAccessWithLargeCapacity);
            }

            if (inheritability < HandleInheritability.None || inheritability > HandleInheritability.Inheritable)
            {
                throw new ArgumentOutOfRangeException(nameof(inheritability));
            }

            // flush any bytes written to the FileStream buffer so that we can see them in our MemoryMappedFile
            fileStream.Flush();

            if (capacity == DefaultSize)
            {
                capacity = fileStream.Length;
            }

            // one can always create a small view if they do not want to map an entire file
            if (fileStream.Length > capacity)
            {
                throw new ArgumentOutOfRangeException(nameof(capacity), SR.ArgumentOutOfRange_CapacityGEFileSizeRequired);
            }

            SafeMemoryMappedFileHandle handle = CreateCore(fileStream, mapName, inheritability,
                                                           access, MemoryMappedFileOptions.None, capacity);

            return(new MemoryMappedFile(handle, fileStream, leaveOpen));
        }
Beispiel #3
0
        public static MemoryMappedFile CreateFromFile(String path, FileMode mode, String mapName, Int64 capacity,
                                                      MemoryMappedFileAccess access)
        {
            if (path == null)
            {
                throw new ArgumentNullException("path");
            }

            if (mapName != null && mapName.Length == 0)
            {
                throw new ArgumentException(SR.GetString(SR.Argument_MapNameEmptyString));
            }

            if (capacity < 0)
            {
                throw new ArgumentOutOfRangeException("capacity", SR.GetString(SR.ArgumentOutOfRange_PositiveOrDefaultCapacityRequired));
            }

            if (access < MemoryMappedFileAccess.ReadWrite ||
                access > MemoryMappedFileAccess.ReadWriteExecute)
            {
                throw new ArgumentOutOfRangeException("access");
            }

            if (mode == FileMode.Append)
            {
                throw new ArgumentException(SR.GetString(SR.Argument_NewMMFAppendModeNotAllowed), "mode");
            }
            if (access == MemoryMappedFileAccess.Write)
            {
                throw new ArgumentException(SR.GetString(SR.Argument_NewMMFWriteAccessNotAllowed), "access");
            }

            bool       existed    = File.Exists(path);
            FileStream fileStream = new FileStream(path, mode, GetFileStreamFileSystemRights(access), FileShare.None, 0x1000, FileOptions.None);

            if (capacity == 0 && fileStream.Length == 0)
            {
                CleanupFile(fileStream, existed, path);
                throw new ArgumentException(SR.GetString(SR.Argument_EmptyFile));
            }

            if (access == MemoryMappedFileAccess.Read && capacity > fileStream.Length)
            {
                CleanupFile(fileStream, existed, path);
                throw new ArgumentException(SR.GetString(SR.Argument_ReadAccessWithLargeCapacity));
            }

            if (capacity == DefaultSize)
            {
                capacity = fileStream.Length;
            }

            // one can always create a small view if they do not want to map an entire file
            if (fileStream.Length > capacity)
            {
                CleanupFile(fileStream, existed, path);
                throw new ArgumentOutOfRangeException("capacity", SR.GetString(SR.ArgumentOutOfRange_CapacityGEFileSizeRequired));
            }

            SafeMemoryMappedFileHandle handle = null;

            try {
                handle = CreateCore(fileStream.SafeFileHandle, mapName, HandleInheritability.None, null,
                                    access, MemoryMappedFileOptions.None, capacity);
            }
            catch {
                CleanupFile(fileStream, existed, path);
                throw;
            }

            Debug.Assert(handle != null && !handle.IsInvalid);
            return(new MemoryMappedFile(handle, fileStream, false));
        }
Beispiel #4
0
        private static SafeMemoryMappedFileHandle CreateOrOpenCore(SafeFileHandle fileHandle, String mapName,
                                                                   HandleInheritability inheritability,
                                                                   MemoryMappedFileSecurity memoryMappedFileSecurity,
                                                                   MemoryMappedFileAccess access, MemoryMappedFileOptions options,
                                                                   Int64 capacity)
        {
            Debug.Assert(access != MemoryMappedFileAccess.Write, "Callers requesting write access shouldn't try to create a mmf");

            SafeMemoryMappedFileHandle handle = null;
            Object pinningHandle;

            UnsafeNativeMethods.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(inheritability, memoryMappedFileSecurity, out pinningHandle);

            // split the long into two ints
            Int32 capacityLow  = (Int32)(capacity & 0x00000000FFFFFFFFL);
            Int32 capacityHigh = (Int32)(capacity >> 32);

            try {
                int waitRetries = 14;   //((2^13)-1)*10ms == approximately 1.4mins
                int waitSleep   = 0;

                // keep looping until we've exhausted retries or break as soon we we get valid handle
                while (waitRetries > 0)
                {
                    // try to create
                    handle = UnsafeNativeMethods.CreateFileMapping(fileHandle, secAttrs,
                                                                   GetPageAccess(access) | (int)options, capacityHigh, capacityLow, mapName);

                    Int32 createErrorCode = Marshal.GetLastWin32Error();
                    if (!handle.IsInvalid)
                    {
                        break;
                    }
                    else
                    {
                        if (createErrorCode != UnsafeNativeMethods.ERROR_ACCESS_DENIED)
                        {
                            __Error.WinIOError(createErrorCode, String.Empty);
                        }

                        // the mapname exists but our ACL is preventing us from opening it with CreateFileMapping.
                        // Let's try to open it with OpenFileMapping.
                        handle.SetHandleAsInvalid();
                    }

                    // try to open
                    handle = UnsafeNativeMethods.OpenFileMapping(GetFileMapAccess(access), (inheritability &
                                                                                            HandleInheritability.Inheritable) != 0, mapName);

                    Int32 openErrorCode = Marshal.GetLastWin32Error();

                    // valid handle
                    if (!handle.IsInvalid)
                    {
                        break;
                    }
                    // didn't get valid handle; have to retry
                    else
                    {
                        if (openErrorCode != UnsafeNativeMethods.ERROR_FILE_NOT_FOUND)
                        {
                            __Error.WinIOError(openErrorCode, String.Empty);
                        }

                        // increase wait time
                        --waitRetries;
                        if (waitSleep == 0)
                        {
                            waitSleep = 10;
                        }
                        else
                        {
                            System.Threading.Thread.Sleep(waitSleep);
                            waitSleep *= 2;
                        }
                    }
                }

                // finished retrying but couldn't create or open
                if (handle == null || handle.IsInvalid)
                {
                    throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_CantCreateFileMapping));
                }
            }

            finally {
                if (pinningHandle != null)
                {
                    GCHandle pinHandle = (GCHandle)pinningHandle;
                    pinHandle.Free();
                }
            }
            return(handle);
        }
 internal static extern int GetFileSize(SafeMemoryMappedFileHandle hFile, out int highSize);
 internal static partial SafeMemoryMappedViewHandle MapViewOfFile(
     SafeMemoryMappedFileHandle hFileMappingObject,
     int dwDesiredAccess,
     int dwFileOffsetHigh,
     int dwFileOffsetLow,
     UIntPtr dwNumberOfBytesToMap);
Beispiel #7
0
        internal unsafe static MemoryMappedView CreateView(SafeMemoryMappedFileHandle memMappedFileHandle,
                                                           MemoryMappedFileAccess access, Int64 offset, Int64 size)
        {
            // MapViewOfFile can only create views that start at a multiple of the system memory allocation
            // granularity. We decided to hide this restriction form the user by creating larger views than the
            // user requested and hiding the parts that the user did not request.  extraMemNeeded is the amount of
            // extra memory we allocate before the start of the requested view. MapViewOfFile will also round the
            // capacity of the view to the nearest multiple of the system page size.  Once again, we hide this
            // from the user by preventing them from writing to any memory that they did not request.
            ulong extraMemNeeded = (ulong)offset % (ulong)MemoryMappedFile.GetSystemPageAllocationGranularity();

            // newOffset takes into account the fact that we have some extra memory allocated before the requested view
            ulong newOffset = (ulong)offset - extraMemNeeded;

            Debug.Assert(newOffset >= 0, "newOffset = (offset - extraMemNeeded) < 0");

            // determine size to pass to MapViewOfFile
            ulong nativeSize;

            if (size != MemoryMappedFile.DefaultSize)
            {
                nativeSize = (ulong)size + (ulong)extraMemNeeded;
            }
            else
            {
                nativeSize = 0;
            }

            if (IntPtr.Size == 4 && nativeSize > UInt32.MaxValue)
            {
                throw new ArgumentOutOfRangeException("size", SR.GetString(SR.ArgumentOutOfRange_CapacityLargerThanLogicalAddressSpaceNotAllowed));
            }

            // if request is >= than total virtual, then MapViewOfFile will fail with meaningless error message
            // "the parameter is incorrect"; this provides better error message in advance
            UnsafeNativeMethods.MEMORYSTATUSEX memStatus = new UnsafeNativeMethods.MEMORYSTATUSEX();
            bool  result       = UnsafeNativeMethods.GlobalMemoryStatusEx(memStatus);
            ulong totalVirtual = memStatus.ullTotalVirtual;

            if (nativeSize >= totalVirtual)
            {
                throw new IOException(SR.GetString(SR.IO_NotEnoughMemory));
            }

            // split the Int64 into two ints
            uint offsetLow  = (uint)(newOffset & 0x00000000FFFFFFFFL);
            uint offsetHigh = (uint)(newOffset >> 32);

            // create the view
            SafeMemoryMappedViewHandle viewHandle = UnsafeNativeMethods.MapViewOfFile(memMappedFileHandle,
                                                                                      MemoryMappedFile.GetFileMapAccess(access), offsetHigh, offsetLow, new UIntPtr(nativeSize));

            if (viewHandle.IsInvalid)
            {
                __Error.WinIOError(Marshal.GetLastWin32Error(), String.Empty);
            }

            // Query the view for its size and allocation type
            UnsafeNativeMethods.MEMORY_BASIC_INFORMATION viewInfo = new UnsafeNativeMethods.MEMORY_BASIC_INFORMATION();
            UnsafeNativeMethods.VirtualQuery(viewHandle, ref viewInfo, (IntPtr)Marshal.SizeOf(viewInfo));
            ulong viewSize = (ulong)viewInfo.RegionSize;


            // allocate the pages if we were using the MemoryMappedFileOptions.DelayAllocatePages option
            if ((viewInfo.State & UnsafeNativeMethods.MEM_RESERVE) != 0)
            {
                IntPtr tempHandle = UnsafeNativeMethods.VirtualAlloc(viewHandle, (UIntPtr)viewSize, UnsafeNativeMethods.MEM_COMMIT,
                                                                     MemoryMappedFile.GetPageAccess(access));
                int lastError = Marshal.GetLastWin32Error();
                if (viewHandle.IsInvalid)
                {
                    __Error.WinIOError(lastError, String.Empty);
                }
            }

            // if the user specified DefaultSize as the size, we need to get the actual size
            if (size == MemoryMappedFile.DefaultSize)
            {
                size = (Int64)(viewSize - extraMemNeeded);
            }
            else
            {
                Debug.Assert(viewSize >= (ulong)size, "viewSize < size");
            }

            viewHandle.Initialize((ulong)size + extraMemNeeded);
            MemoryMappedView mmv = new MemoryMappedView(viewHandle, (long)extraMemNeeded, size, access);

            return(mmv);
        }
        public static unsafe MemoryMappedView CreateView(SafeMemoryMappedFileHandle memMappedFileHandle,
                                                         MemoryMappedFileAccess access, long offset, long size)
        {
            // MapViewOfFile can only create views that start at a multiple of the system memory allocation
            // granularity. We decided to hide this restriction from the user by creating larger views than the
            // user requested and hiding the parts that the user did not request.  extraMemNeeded is the amount of
            // extra memory we allocate before the start of the requested view. MapViewOfFile will also round the
            // capacity of the view to the nearest multiple of the system page size.  Once again, we hide this
            // from the user by preventing them from writing to any memory that they did not request.
            ulong nativeSize;
            long  extraMemNeeded, newOffset;

            ValidateSizeAndOffset(
                size, offset, GetSystemPageAllocationGranularity(),
                out nativeSize, out extraMemNeeded, out newOffset);

            // if request is >= than total virtual, then MapViewOfFile will fail with meaningless error message
            // "the parameter is incorrect"; this provides better error message in advance
            Interop.CheckForAvailableVirtualMemory(nativeSize);

            // create the view
            SafeMemoryMappedViewHandle viewHandle = Interop.MapViewOfFile(memMappedFileHandle,
                                                                          (int)MemoryMappedFile.GetFileMapAccess(access), newOffset, new UIntPtr(nativeSize));

            if (viewHandle.IsInvalid)
            {
                viewHandle.Dispose();
                throw Win32Marshal.GetExceptionForLastWin32Error();
            }

            // Query the view for its size and allocation type
            Interop.Kernel32.MEMORY_BASIC_INFORMATION viewInfo = default;
            Interop.Kernel32.VirtualQuery(viewHandle, ref viewInfo, (UIntPtr)Marshal.SizeOf(viewInfo));
            ulong viewSize = (ulong)viewInfo.RegionSize;

            // Allocate the pages if we were using the MemoryMappedFileOptions.DelayAllocatePages option
            // OR check if the allocated view size is smaller than the expected native size
            // If multiple overlapping views are created over the file mapping object, the pages in a given region
            // could have different attributes(MEM_RESERVE OR MEM_COMMIT) as MapViewOfFile preserves coherence between
            // views created on a mapping object backed by same file.
            // In which case, the viewSize will be smaller than nativeSize required and viewState could be MEM_COMMIT
            // but more pages may need to be committed in the region.
            // This is because, VirtualQuery function(that internally invokes VirtualQueryEx function) returns the attributes
            // and size of the region of pages with matching attributes starting from base address.
            // VirtualQueryEx: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366907(v=vs.85).aspx
            if (((viewInfo.State & Interop.Kernel32.MemOptions.MEM_RESERVE) != 0) || ((ulong)viewSize < (ulong)nativeSize))
            {
                IntPtr tempHandle = Interop.VirtualAlloc(
                    viewHandle, (UIntPtr)(nativeSize != MemoryMappedFile.DefaultSize ? nativeSize : viewSize),
                    Interop.Kernel32.MemOptions.MEM_COMMIT, MemoryMappedFile.GetPageAccess(access));
                int lastError = Marshal.GetLastWin32Error();
                if (viewHandle.IsInvalid)
                {
                    viewHandle.Dispose();
                    throw Win32Marshal.GetExceptionForWin32Error(lastError);
                }
                // again query the view for its new size
                viewInfo = default;
                Interop.Kernel32.VirtualQuery(viewHandle, ref viewInfo, (UIntPtr)Marshal.SizeOf(viewInfo));
                viewSize = (ulong)viewInfo.RegionSize;
            }

            // if the user specified DefaultSize as the size, we need to get the actual size
            if (size == MemoryMappedFile.DefaultSize)
            {
                size = (long)(viewSize - (ulong)extraMemNeeded);
            }
            else
            {
                Debug.Assert(viewSize >= (ulong)size, "viewSize < size");
            }

            viewHandle.Initialize((ulong)size + (ulong)extraMemNeeded);
            return(new MemoryMappedView(viewHandle, extraMemNeeded, size, access));
        }
        private static SafeMemoryMappedFileHandle CreateOrOpenCore(
            string mapName, HandleInheritability inheritability, MemoryMappedFileAccess access,
            MemoryMappedFileOptions options, long capacity)
        {
            /// Try to open the file if it exists -- this requires a bit more work. Loop until we can
            /// either create or open a memory mapped file up to a timeout. CreateFileMapping may fail
            /// if the file exists and we have non-null security attributes, in which case we need to
            /// use OpenFileMapping.  But, there exists a race condition because the memory mapped file
            /// may have closed inbetween the two calls -- hence the loop.
            ///
            /// The retry/timeout logic increases the wait time each pass through the loop and times
            /// out in approximately 1.4 minutes. If after retrying, a MMF handle still hasn't been opened,
            /// throw an InvalidOperationException.

            Debug.Assert(access != MemoryMappedFileAccess.Write, "Callers requesting write access shouldn't try to create a mmf");

            SafeMemoryMappedFileHandle handle = null;

            Interop.mincore.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(inheritability);

            // split the long into two ints
            int capacityLow  = unchecked ((int)(capacity & 0x00000000FFFFFFFFL));
            int capacityHigh = unchecked ((int)(capacity >> 32));

            int waitRetries = 14;   //((2^13)-1)*10ms == approximately 1.4mins
            int waitSleep   = 0;

            // keep looping until we've exhausted retries or break as soon we we get valid handle
            while (waitRetries > 0)
            {
                // try to create
                handle = Interop.mincore.CreateFileMapping(INVALID_HANDLE_VALUE, ref secAttrs,
                                                           GetPageAccess(access) | (int)options, capacityHigh, capacityLow, mapName);

                if (!handle.IsInvalid)
                {
                    break;
                }
                else
                {
                    int createErrorCode = Marshal.GetLastWin32Error();
                    if (createErrorCode != Interop.mincore.Errors.ERROR_ACCESS_DENIED)
                    {
                        throw Win32Marshal.GetExceptionForWin32Error(createErrorCode);
                    }
                }

                // try to open
                handle = Interop.mincore.OpenFileMapping(GetFileMapAccess(access), (inheritability &
                                                                                    HandleInheritability.Inheritable) != 0, mapName);

                // valid handle
                if (!handle.IsInvalid)
                {
                    break;
                }
                // didn't get valid handle; have to retry
                else
                {
                    int openErrorCode = Marshal.GetLastWin32Error();
                    if (openErrorCode != Interop.mincore.Errors.ERROR_FILE_NOT_FOUND)
                    {
                        throw Win32Marshal.GetExceptionForWin32Error(openErrorCode);
                    }

                    // increase wait time
                    --waitRetries;
                    if (waitSleep == 0)
                    {
                        waitSleep = 10;
                    }
                    else
                    {
                        ThreadSleep(waitSleep);
                        waitSleep *= 2;
                    }
                }
            }

            // finished retrying but couldn't create or open
            if (handle == null || handle.IsInvalid)
            {
                throw new InvalidOperationException(SR.InvalidOperation_CantCreateFileMapping);
            }

            return(handle);
        }
Beispiel #10
0
 internal static extern SafeMemoryMappedViewHandle MapViewOfFile(
     SafeMemoryMappedFileHandle hFileMappingObject,
     FileMapAccess dwDesiredAccess,
     UInt32 dwFileOffsetHigh,
     UInt32 dwFileOffsetLow,
     UIntPtr dwNumberOfBytesToMap);
        public unsafe static MemoryMappedView CreateView(
            SafeMemoryMappedFileHandle memMappedFileHandle, MemoryMappedFileAccess access,
            long requestedOffset, long requestedSize)
        {
            if (requestedOffset > memMappedFileHandle._capacity)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (requestedSize > MaxProcessAddressSpace)
            {
                throw new IOException(SR.ArgumentOutOfRange_CapacityLargerThanLogicalAddressSpaceNotAllowed);
            }
            if (requestedOffset + requestedSize > memMappedFileHandle._capacity)
            {
                throw new UnauthorizedAccessException();
            }
            if (memMappedFileHandle.IsClosed)
            {
                throw new ObjectDisposedException(typeof(MemoryMappedFile).Name);
            }

            if (requestedSize == MemoryMappedFile.DefaultSize)
            {
                requestedSize = memMappedFileHandle._capacity - requestedOffset;
            }

            // mmap can only create views that start at a multiple of the page size. As on Windows,
            // we hide this restriction form the user by creating larger views than the user requested and hiding the parts
            // that the user did not request.  extraMemNeeded is the amount of extra memory we allocate before the start of the
            // requested view. (mmap may round up the actual length such that it is also page-aligned; we hide that by using
            // the right size and not extending the size to be page-aligned.)
            ulong nativeSize, extraMemNeeded, nativeOffset;
            int   pageSize = Interop.libc.sysconf(Interop.libc.SysConfNames._SC_PAGESIZE);

            ValidateSizeAndOffset(
                requestedSize, requestedOffset, pageSize,
                out nativeSize, out extraMemNeeded, out nativeOffset);
            if (nativeSize == 0)
            {
                nativeSize = (ulong)pageSize;
            }

            bool gotRefOnHandle = false;

            try
            {
                // Determine whether to create the pages as private or as shared; the former is used for copy-on-write.
                Interop.libc.MemoryMappedFlags flags = (memMappedFileHandle._access == MemoryMappedFileAccess.CopyOnWrite) ?
                                                       Interop.libc.MemoryMappedFlags.MAP_PRIVATE :
                                                       Interop.libc.MemoryMappedFlags.MAP_SHARED;

                // If we have a file handle, get the file descriptor from it.  If the handle is null,
                // we'll use an anonymous backing store for the map.
                int fd;
                if (memMappedFileHandle._fileHandle != null)
                {
                    // Get the file descriptor from the SafeFileHandle
                    memMappedFileHandle._fileHandle.DangerousAddRef(ref gotRefOnHandle);
                    Debug.Assert(gotRefOnHandle);
                    fd = (int)memMappedFileHandle._fileHandle.DangerousGetHandle();
                    Debug.Assert(fd >= 0);
                }
                else
                {
                    Debug.Assert(!gotRefOnHandle);
                    fd     = -1;
                    flags |= Interop.libc.MemoryMappedFlags.MAP_ANONYMOUS;
                }

                // Nothing to do for options.DelayAllocatePages, since we're only creating the map
                // with mmap when creating the view.

                // Verify that the requested view permissions don't exceed the map's permissions
                Interop.libc.MemoryMappedProtections viewProtForVerification = GetProtections(access, forVerification: true);
                Interop.libc.MemoryMappedProtections mapProtForVerification  = GetProtections(memMappedFileHandle._access, forVerification: true);
                if ((viewProtForVerification & mapProtForVerification) != viewProtForVerification)
                {
                    throw new UnauthorizedAccessException(viewProtForVerification + " <> " + mapProtForVerification);
                }

                // Create the map
                IntPtr addr = Interop.libc.mmap(
                    IntPtr.Zero,                                    // don't specify an address; let the system choose one
                    (IntPtr)nativeSize,                             // specify the rounded-size we computed so as to page align; size + extraMemNeeded
                    GetProtections(access, forVerification: false), // viewProtections is strictly less than mapProtections, so use viewProtections
                    flags,
                    fd,                                             // mmap adds a ref count to the fd, so there's no need to dup it.
                    (long)nativeOffset);                            // specify the rounded-offset we computed so as to page align; offset - extraMemNeeded
                if ((long)addr < 0)
                {
                    throw Interop.GetExceptionForIoErrno(Marshal.GetLastWin32Error());
                }

                // Based on the HandleInheritability, try to prevent the memory-mapped region
                // from being inherited by a forked process
                if (memMappedFileHandle._inheritability == HandleInheritability.None)
                {
                    int adviseResult = Interop.libc.madvise(addr, (IntPtr)nativeSize, Interop.libc.MemoryMappedAdvice.MADV_DONTFORK);
                    Debug.Assert(adviseResult == 0); // In release, ignore failures from advise; it's just a hint, anyway.
                }

                // Create and return the view handle
                var viewHandle = new SafeMemoryMappedViewHandle(addr, ownsHandle: true);
                viewHandle.Initialize(nativeSize);
                return(new MemoryMappedView(
                           viewHandle,
                           (long)extraMemNeeded, // the view points to offset - extraMemNeeded, so we need to shift back by extraMemNeeded
                           requestedSize,        // only allow access to the actual size requested
                           access));
            }
            finally
            {
                if (gotRefOnHandle)
                {
                    memMappedFileHandle._fileHandle.DangerousRelease();
                }
            }
        }
 internal MemoryMappedFileSecurity(SafeMemoryMappedFileHandle safeHandle, AccessControlSections includeSections) : base(false, ResourceType.KernelObject, safeHandle, includeSections)
 {
 }
 internal static extern SafeMemoryMappedViewHandle MapViewOfFile(SafeMemoryMappedFileHandle handle, int dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, UIntPtr dwNumberOfBytesToMap);
Beispiel #14
0
        public unsafe static MemoryMappedView CreateView(
            SafeMemoryMappedFileHandle memMappedFileHandle, MemoryMappedFileAccess access,
            long requestedOffset, long requestedSize)
        {
            if (requestedOffset > memMappedFileHandle._capacity)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (requestedSize > MaxProcessAddressSpace)
            {
                throw new IOException(SR.ArgumentOutOfRange_CapacityLargerThanLogicalAddressSpaceNotAllowed);
            }
            if (requestedOffset + requestedSize > memMappedFileHandle._capacity)
            {
                throw new UnauthorizedAccessException();
            }
            if (memMappedFileHandle.IsClosed)
            {
                throw new ObjectDisposedException(typeof(MemoryMappedFile).Name);
            }

            if (requestedSize == MemoryMappedFile.DefaultSize)
            {
                requestedSize = memMappedFileHandle._capacity - requestedOffset;
            }

            // mmap can only create views that start at a multiple of the page size. As on Windows,
            // we hide this restriction form the user by creating larger views than the user requested and hiding the parts
            // that the user did not request.  extraMemNeeded is the amount of extra memory we allocate before the start of the
            // requested view. (mmap may round up the actual length such that it is also page-aligned; we hide that by using
            // the right size and not extending the size to be page-aligned.)
            ulong nativeSize;
            long  extraMemNeeded, nativeOffset;
            long  pageSize = Interop.Sys.SysConf(Interop.Sys.SysConfName._SC_PAGESIZE);

            Debug.Assert(pageSize > 0);
            ValidateSizeAndOffset(
                requestedSize, requestedOffset, pageSize,
                out nativeSize, out extraMemNeeded, out nativeOffset);

            // Determine whether to create the pages as private or as shared; the former is used for copy-on-write.
            Interop.Sys.MemoryMappedFlags flags =
                (memMappedFileHandle._access == MemoryMappedFileAccess.CopyOnWrite || access == MemoryMappedFileAccess.CopyOnWrite) ?
                Interop.Sys.MemoryMappedFlags.MAP_PRIVATE :
                Interop.Sys.MemoryMappedFlags.MAP_SHARED;

            // If we have a file handle, get the file descriptor from it.  If the handle is null,
            // we'll use an anonymous backing store for the map.
            SafeFileHandle fd;

            if (memMappedFileHandle._fileStream != null)
            {
                // Get the file descriptor from the SafeFileHandle
                fd = memMappedFileHandle._fileStream.SafeFileHandle;
                Debug.Assert(!fd.IsInvalid);
            }
            else
            {
                fd     = new SafeFileHandle(new IntPtr(-1), false);
                flags |= Interop.Sys.MemoryMappedFlags.MAP_ANONYMOUS;
            }

            // Nothing to do for options.DelayAllocatePages, since we're only creating the map
            // with mmap when creating the view.

            // Verify that the requested view permissions don't exceed the map's permissions
            Interop.Sys.MemoryMappedProtections viewProtForVerification = GetProtections(access, forVerification: true);
            Interop.Sys.MemoryMappedProtections mapProtForVerification  = GetProtections(memMappedFileHandle._access, forVerification: true);
            if ((viewProtForVerification & mapProtForVerification) != viewProtForVerification)
            {
                throw new UnauthorizedAccessException();
            }

            // viewProtections is strictly less than mapProtections, so use viewProtections for actually creating the map.
            Interop.Sys.MemoryMappedProtections viewProtForCreation = GetProtections(access, forVerification: false);

            // Create the map
            IntPtr addr = IntPtr.Zero;

            if (nativeSize > 0)
            {
                addr = Interop.Sys.MMap(
                    IntPtr.Zero,         // don't specify an address; let the system choose one
                    nativeSize,          // specify the rounded-size we computed so as to page align; size + extraMemNeeded
                    viewProtForCreation,
                    flags,
                    fd,                  // mmap adds a ref count to the fd, so there's no need to dup it.
                    nativeOffset);       // specify the rounded-offset we computed so as to page align; offset - extraMemNeeded
            }
            else
            {
                // There are some corner cases where the .NET API allows the requested size to be zero, e.g. the caller is
                // creating a map at the end of the capacity.  We can't pass 0 to mmap, as that'll fail with EINVAL, nor can
                // we create a map that extends beyond the end of the underlying file, as that'll fail on some platforms at the
                // time of the map's creation.  Instead, since there's no data to be read/written, it doesn't actually matter
                // what backs the view, so we just create an anonymous mapping.
                addr = Interop.Sys.MMap(
                    IntPtr.Zero,
                    1,         // any length that's greater than zero will suffice
                    viewProtForCreation,
                    flags | Interop.Sys.MemoryMappedFlags.MAP_ANONYMOUS,
                    new SafeFileHandle(new IntPtr(-1), false),        // ignore the actual fd even if there was one
                    0);
                requestedSize  = 0;
                extraMemNeeded = 0;
            }
            if (addr == IntPtr.Zero) // note that shim uses null pointer, not non-null MAP_FAILED sentinel
            {
                throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo());
            }

            // Based on the HandleInheritability, try to prevent the memory-mapped region
            // from being inherited by a forked process
            if (memMappedFileHandle._inheritability == HandleInheritability.None)
            {
                DisableForkingIfPossible(addr, nativeSize);
            }

            // Create and return the view handle
            var viewHandle = new SafeMemoryMappedViewHandle(addr, ownsHandle: true);

            viewHandle.Initialize((ulong)nativeSize);
            return(new MemoryMappedView(
                       viewHandle,
                       extraMemNeeded, // the view points to offset - extraMemNeeded, so we need to shift back by extraMemNeeded
                       requestedSize,  // only allow access to the actual size requested
                       access));
        }
 internal static extern SafeMemoryMappedViewHandle MapViewOfFileFromApp(
     SafeMemoryMappedFileHandle hFileMappingObject,
     int DesiredAccess,
     long FileOffset,
     UIntPtr NumberOfBytesToMap);
        public unsafe static MemoryMappedView CreateView(SafeMemoryMappedFileHandle memMappedFileHandle,
                                                         MemoryMappedFileAccess access, Int64 offset, Int64 size)
        {
            // MapViewOfFile can only create views that start at a multiple of the system memory allocation
            // granularity. We decided to hide this restriction form the user by creating larger views than the
            // user requested and hiding the parts that the user did not request.  extraMemNeeded is the amount of
            // extra memory we allocate before the start of the requested view. MapViewOfFile will also round the
            // capacity of the view to the nearest multiple of the system page size.  Once again, we hide this
            // from the user by preventing them from writing to any memory that they did not request.
            ulong extraMemNeeded = (ulong)offset % (ulong)GetSystemPageAllocationGranularity();

            // newOffset takes into account the fact that we have some extra memory allocated before the requested view
            ulong newOffset = (ulong)offset - extraMemNeeded;

            Debug.Assert(newOffset >= 0, "newOffset = (offset - extraMemNeeded) < 0");

            // determine size to pass to MapViewOfFile
            ulong nativeSize = (size != MemoryMappedFile.DefaultSize) ?
                               (ulong)size + (ulong)extraMemNeeded :
                               0;

            if (IntPtr.Size == 4 && nativeSize > UInt32.MaxValue)
            {
                throw new ArgumentOutOfRangeException("size", SR.ArgumentOutOfRange_CapacityLargerThanLogicalAddressSpaceNotAllowed);
            }

            // if request is >= than total virtual, then MapViewOfFile will fail with meaningless error message
            // "the parameter is incorrect"; this provides better error message in advance
            Interop.MEMORYSTATUSEX memStatus;
            memStatus.dwLength = (uint)sizeof(Interop.MEMORYSTATUSEX);
            Interop.mincore.GlobalMemoryStatusEx(out memStatus);
            ulong totalVirtual = memStatus.ullTotalVirtual;

            if (nativeSize >= totalVirtual)
            {
                throw new IOException(SR.IO_NotEnoughMemory);
            }

            // split the Int64 into two ints
            int offsetLow  = unchecked ((int)(newOffset & 0x00000000FFFFFFFFL));
            int offsetHigh = unchecked ((int)(newOffset >> 32));

            // create the view
            SafeMemoryMappedViewHandle viewHandle = Interop.mincore.MapViewOfFile(memMappedFileHandle,
                                                                                  (int)MemoryMappedFile.GetFileMapAccess(access), offsetHigh, offsetLow, new UIntPtr(nativeSize));

            if (viewHandle.IsInvalid)
            {
                throw Win32Marshal.GetExceptionForLastWin32Error();
            }

            // Query the view for its size and allocation type
            Interop.MEMORY_BASIC_INFORMATION viewInfo = new Interop.MEMORY_BASIC_INFORMATION();
            Interop.mincore.VirtualQuery(viewHandle, ref viewInfo, (UIntPtr)Marshal.SizeOf(viewInfo));
            ulong viewSize = (ulong)viewInfo.RegionSize;

            // Allocate the pages if we were using the MemoryMappedFileOptions.DelayAllocatePages option
            // OR check if the allocated view size is smaller than the expected native size
            // If multiple overlapping views are created over the file mapping object, the pages in a given region
            // could have different attributes(MEM_RESERVE OR MEM_COMMIT) as MapViewOfFile preserves coherence between
            // views created on a mapping object backed by same file.
            // In which case, the viewSize will be smaller than nativeSize required and viewState could be MEM_COMMIT
            // but more pages may need to be committed in the region.
            // This is because, VirtualQuery function(that internally invokes VirtualQueryEx function) returns the attributes
            // and size of the region of pages with matching attributes starting from base address.
            // VirtualQueryEx: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366907(v=vs.85).aspx
            if (((viewInfo.State & Interop.MEM_RESERVE) != 0) || (viewSize < nativeSize))
            {
                IntPtr tempHandle = Interop.mincore.VirtualAlloc(viewHandle, (UIntPtr)nativeSize, Interop.MEM_COMMIT,
                                                                 MemoryMappedFile.GetPageAccess(access));
                int lastError = Marshal.GetLastWin32Error();
                if (viewHandle.IsInvalid)
                {
                    throw Win32Marshal.GetExceptionForWin32Error(lastError);
                }
                // again query the view for its new size
                viewInfo = new Interop.MEMORY_BASIC_INFORMATION();
                Interop.mincore.VirtualQuery(viewHandle, ref viewInfo, (UIntPtr)Marshal.SizeOf(viewInfo));
                viewSize = (ulong)viewInfo.RegionSize;
            }

            // if the user specified DefaultSize as the size, we need to get the actual size
            if (size == MemoryMappedFile.DefaultSize)
            {
                size = (Int64)(viewSize - extraMemNeeded);
            }
            else
            {
                Debug.Assert(viewSize >= (ulong)size, "viewSize < size");
            }

            viewHandle.Initialize((ulong)size + extraMemNeeded);
            return(new MemoryMappedView(viewHandle, (long)extraMemNeeded, size, access));
        }
Beispiel #17
0
 public static extern SafeMemoryMappedViewHandle MapViewOfFile(SafeMemoryMappedFileHandle hFileMappingObject,
                                                               uint dwDesiredAccess,
                                                               uint dwFileOffsetHigh,
                                                               uint dwFileOffsetLow,
                                                               IntPtr dwNumberOfBytesToMap);
 private MemoryMappedFile(SafeMemoryMappedFileHandle handle)
 {
     this._handle = handle;
 }
Beispiel #19
0
 public unsafe static MemoryMappedView CreateView(
     SafeMemoryMappedFileHandle memMappedFileHandle, MemoryMappedFileAccess access, Int64 offset, Int64 size)
 {
     throw NotImplemented.ByDesign; // TODO: Implement this
 }