Imported Upstream version 4.0.0~alpha1

Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
Jo Shields
2015-04-07 09:35:12 +01:00
parent 283343f570
commit 3c1f479b9d
22469 changed files with 2931443 additions and 869343 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: Enums
**
**
** Purpose: Enums shared by IO classes
**
**
===========================================================*/
using System;
using System.Text;
namespace System.IO {
[Serializable]
public enum HandleInheritability {
None = 0,
Inheritable = 1,
}
}

View File

@@ -0,0 +1,38 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: LogStream
**
===========================================================*/
using System;
namespace System.IO {
internal enum LogRetentionOption {
// One file with no maxFileSize
SingleFileUnboundedSize = 2,
// One file with a maxFileSize
SingleFileBoundedSize = 4,
// Infinite number of sequential files, each with maxFileSize
// When MaxFileSize is reached, writing starts in a new file with an incremented integer suffix.
UnlimitedSequentialFiles = 0,
// Finite number of sequential files, each with maxFileSize
LimitedSequentialFiles = 3,
// Finite number of circular sequential files, each with maxFileSize.
// When MaxFileSize is reached, writing starts in a new file with an incremented integer suffix.
// When MaxNumberOfFiles is reached first file is overwritten. Files are then incrementally overwritten in a circular manner.
LimitedCircularFiles = 1
}
}

View File

@@ -0,0 +1,469 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: LogStream
**
===========================================================*/
using System;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Runtime.InteropServices;
using System.Runtime.Remoting.Messaging;
using System.Runtime.CompilerServices;
using System.Globalization;
using System.Runtime.Versioning;
using System.Diagnostics;
using System.Diagnostics.Contracts;
namespace System.IO {
// This stream has very limited support to enable EventSchemaTraceListener
// Eventually we might want to add more functionality and expose this type
internal class LogStream : BufferedStream2
{
internal const long DefaultFileSize = 10*1000*1024;
internal const int DefaultNumberOfFiles = 2;
internal const LogRetentionOption DefaultRetention = LogRetentionOption.SingleFileUnboundedSize;
// Retention policy
private const int _retentionRetryThreshold = 2;
private LogRetentionOption _retention;
private long _maxFileSize = DefaultFileSize;
private int _maxNumberOfFiles = DefaultNumberOfFiles;
private int _currentFileNum = 1;
bool _disableLogging;
int _retentionRetryCount;
private bool _canRead;
private bool _canWrite;
private bool _canSeek;
[SecurityCritical]
private SafeFileHandle _handle;
private String _fileName; // Fully qualified file name.
string _fileNameWithoutExt;
string _fileExt;
// Save input for retention
string _pathSav;
int _fAccessSav;
FileShare _shareSav;
UnsafeNativeMethods.SECURITY_ATTRIBUTES _secAttrsSav;
FileIOPermissionAccess _secAccessSav;
FileMode _modeSav;
int _flagsAndAttributesSav;
bool _seekToEndSav;
private readonly object m_lockObject = new Object();
//Limited to immediate internal need from EventSchemaTraceListener
//Not param validation done!!
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
[System.Security.SecurityCritical]
internal LogStream(String path, int bufferSize, LogRetentionOption retention, long maxFileSize, int maxNumOfFiles)
{
Debug.Assert(!String.IsNullOrEmpty(path));
// Get absolute path - Security needs this to prevent something
// like trying to create a file in c:\tmp with the name
// "..\WinNT\System32\ntoskrnl.exe". Store it for user convenience.
//String filePath = Path.GetFullPathInternal(path);
String filePath = Path.GetFullPath(path);
_fileName = filePath;
// Prevent access to your disk drives as raw block devices.
if (filePath.StartsWith("\\\\.\\", StringComparison.Ordinal))
throw new NotSupportedException(SR.GetString(SR.NotSupported_IONonFileDevices));
UnsafeNativeMethods.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(FileShare.Read);
// For mitigating local elevation of privilege attack through named pipes
// make sure we always call CreateFile with SECURITY_ANONYMOUS so that the
// named pipe server can't impersonate a high privileged client security context
int flagsAndAttributes = (int)FileOptions.None | (UnsafeNativeMethods.SECURITY_SQOS_PRESENT | UnsafeNativeMethods.SECURITY_ANONYMOUS);
// Only write is enabled
//_canRead = false;
//_canSeek = false;
_canWrite = true;
_pathSav = filePath;
_fAccessSav = UnsafeNativeMethods.GENERIC_WRITE;
_shareSav = FileShare.Read;
_secAttrsSav = secAttrs;
_secAccessSav = FileIOPermissionAccess.Write;
_modeSav = (retention != LogRetentionOption.SingleFileUnboundedSize)? FileMode.Create : FileMode.OpenOrCreate;
_flagsAndAttributesSav = flagsAndAttributes;
_seekToEndSav = (retention != LogRetentionOption.SingleFileUnboundedSize)? false : true;
this.bufferSize = bufferSize;
_retention = retention;
_maxFileSize = maxFileSize;
_maxNumberOfFiles = maxNumOfFiles;
_Init(filePath, _fAccessSav, _shareSav, _secAttrsSav, _secAccessSav, _modeSav, _flagsAndAttributesSav, _seekToEndSav);
}
[System.Security.SecurityCritical]
internal void _Init(String path, int fAccess, FileShare share, UnsafeNativeMethods.SECURITY_ATTRIBUTES secAttrs, FileIOPermissionAccess secAccess,
FileMode mode, int flagsAndAttributes, bool seekToEnd)
{
String filePath = Path.GetFullPath(path);
_fileName = filePath;
new FileIOPermission(secAccess, new String[] { filePath }).Demand();
// Don't pop up a dialog for reading from an emtpy floppy drive
int oldMode = UnsafeNativeMethods.SetErrorMode(UnsafeNativeMethods.SEM_FAILCRITICALERRORS);
try {
_handle = UnsafeNativeMethods.SafeCreateFile(filePath, fAccess, share, secAttrs, mode, flagsAndAttributes, UnsafeNativeMethods.NULL);
int errorCode = Marshal.GetLastWin32Error();
if (_handle.IsInvalid) {
// Return a meaningful exception, using the RELATIVE path to
// the file to avoid returning extra information to the caller
// unless they have path discovery permission, in which case
// the full path is fine & useful.
// We need to give an exception, and preferably it would include
// the fully qualified path name. Do security check here. If
// we fail, give back the msgPath, which should not reveal much.
// While this logic is largely duplicated in
// __Error.WinIOError, we need this for
// IsolatedStorageLogFileStream.
bool canGiveFullPath = false;
try {
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { _fileName }).Demand();
canGiveFullPath = true;
}
catch(SecurityException) {}
if (canGiveFullPath)
__Error.WinIOError(errorCode, _fileName);
else
__Error.WinIOError(errorCode, Path.GetFileName(_fileName));
}
}
finally {
UnsafeNativeMethods.SetErrorMode(oldMode);
}
Debug.Assert(UnsafeNativeMethods.GetFileType(_handle) == UnsafeNativeMethods.FILE_TYPE_DISK, "did someone accidentally removed the device type check from SafeCreateFile P/Invoke wrapper?");
pos = 0;
// For Append mode...
if (seekToEnd) {
SeekCore(0, SeekOrigin.End);
}
}
public override bool CanRead {
[Pure]
get { return _canRead; }
}
public override bool CanWrite {
[Pure]
get { return _canWrite; }
}
public override bool CanSeek {
[Pure]
get { return _canSeek; }
}
public override long Length {
get {
throw new NotSupportedException();
}
}
public override long Position {
get {
throw new NotSupportedException();
}
set {
throw new NotSupportedException();
}
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override int Read(byte[] array, int offset, int count)
{
throw new NotSupportedException();
}
[System.Security.SecurityCritical]
protected override unsafe void WriteCore(byte[] buffer, int offset, int count, bool blockForWrite, out long streamPos) {
Debug.Assert(CanWrite, "CanWrite");
Debug.Assert(buffer != null, "buffer != null");
Debug.Assert(offset >= 0, "offset is negative");
Debug.Assert(count >= 0, "count is negative");
int hr = 0;
int r = WriteFileNative(buffer, offset, count, null, out hr);
if (r == -1) {
// For pipes, ERROR_NO_DATA is not an error, but the pipe is closing.
if (hr == UnsafeNativeMethods.ERROR_NO_DATA) {
r = 0;
}
else {
// ERROR_INVALID_PARAMETER may be returned for writes
// where the position is too large (ie, writing at Int64.MaxValue
// on Win9x) OR for synchronous writes to a handle opened
// asynchronously.
if (hr == UnsafeNativeMethods.ERROR_INVALID_PARAMETER)
throw new IOException(SR.GetString(SR.IO_FileTooLongOrHandleNotSync));
__Error.WinIOError(hr, String.Empty);
}
}
Debug.Assert(r >= 0, "WriteCore is likely broken.");
// update cached position
streamPos = AddUnderlyingStreamPosition((long)r);
EnforceRetentionPolicy(_handle, streamPos);
streamPos = pos;
return;
}
[System.Security.SecurityCritical]
unsafe private int WriteFileNative(byte[] bytes, int offset, int count, NativeOverlapped* overlapped, out int hr) {
if (_handle.IsClosed) __Error.FileNotOpen();
if (_disableLogging) {
hr = 0;
return 0;
}
Debug.Assert(offset >= 0, "offset >= 0");
Debug.Assert(count >= 0, "count >= 0");
Debug.Assert(bytes != null, "bytes != null");
// Don't corrupt memory when multiple threads are erroneously writing
// to this stream simultaneously. (the OS is reading from
// the array we pass to WriteFile, but if we read beyond the end and
// that memory isn't allocated, we could get an AV.)
if (bytes.Length - offset < count)
throw new IndexOutOfRangeException(SR.GetString(SR.IndexOutOfRange_IORaceCondition));
// You can't use the fixed statement on an array of length 0.
if (bytes.Length==0) {
hr = 0;
return 0;
}
int numBytesWritten = 0;
int r = 0;
fixed(byte* p = bytes) {
r = UnsafeNativeMethods.WriteFile(_handle, p + offset, count, out numBytesWritten, overlapped);
}
if (r == 0) {
// We should never silently ---- an error here without some
// extra work. We must make sure that BeginWriteCore won't return an
// IAsyncResult that will cause EndWrite to block, since the OS won't
// call AsyncFSCallback for us.
hr = Marshal.GetLastWin32Error();
// For invalid handles, detect the error and mark our handle
// as closed to give slightly better error messages. Also
// help ensure we avoid handle recycling bugs.
if (hr == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
_handle.SetHandleAsInvalid();
return -1;
}
else
hr = 0;
return numBytesWritten;
}
// This doesn't do argument checking. Necessary for SetLength, which must
// set the file pointer beyond the end of the file. This will update the
// internal position
[System.Security.SecurityCritical]
private long SeekCore(long offset, SeekOrigin origin)
{
Debug.Assert(!_handle.IsClosed, "!_handle.IsClosed");
Debug.Assert(origin>=SeekOrigin.Begin && origin<=SeekOrigin.End, "origin>=SeekOrigin.Begin && origin<=SeekOrigin.End");
int hr = 0;
long ret = 0;
ret = UnsafeNativeMethods.SetFilePointer(_handle, offset, origin, out hr);
if (ret == -1) {
// For invalid handles, detect the error and mark our handle
// as closed to give slightly better error messages. Also
// help ensure we avoid handle recycling bugs.
if (hr == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
_handle.SetHandleAsInvalid();
__Error.WinIOError(hr, String.Empty);
}
UnderlyingStreamPosition = ret;
return ret;
}
[System.Security.SecurityCritical]
protected override void Dispose(bool disposing)
{
// Nothing will be done differently based on whether we are
// disposing vs. finalizing. This is taking advantage of the
// weak ordering between normal finalizable objects & critical
// finalizable objects, which I included in the SafeHandle
// design for LogStream, which would often "just work" when
// finalized.
try {
if (_handle == null || _handle.IsClosed) {
// Make sure BufferedStream doesn't try to flush data on a closed handle
DiscardBuffer();
}
}
finally {
try {
// Cleanup base streams
base.Dispose(disposing);
}
finally {
if (_handle != null && !_handle.IsClosed)
_handle.Dispose();
_handle = null;
_canRead = false;
_canWrite = false;
_canSeek = false;
}
}
}
[System.Security.SecurityCritical]
~LogStream()
{
if (_handle != null) {
Dispose(false);
}
}
[System.Security.SecurityCritical]
private void EnforceRetentionPolicy(SafeFileHandle handle, long lastPos)
{
switch (_retention) {
case LogRetentionOption.LimitedSequentialFiles:
case LogRetentionOption.UnlimitedSequentialFiles:
case LogRetentionOption.LimitedCircularFiles:
if ((lastPos >= _maxFileSize) && (handle == _handle)){
lock (m_lockObject) {
if ((handle != _handle) || (lastPos < _maxFileSize))
return;
_currentFileNum++;
if ((_retention == LogRetentionOption.LimitedCircularFiles) && (_currentFileNum > _maxNumberOfFiles)) {
_currentFileNum = 1;
}
else if ((_retention == LogRetentionOption.LimitedSequentialFiles) && (_currentFileNum > _maxNumberOfFiles)) {
_DisableLogging();
return;
}
if (_fileNameWithoutExt == null) {
_fileNameWithoutExt = Path.Combine(Path.GetDirectoryName(_pathSav), Path.GetFileNameWithoutExtension(_pathSav));
_fileExt = Path.GetExtension(_pathSav);
}
string path = (_currentFileNum == 1)?_pathSav: _fileNameWithoutExt + _currentFileNum.ToString(CultureInfo.InvariantCulture) + _fileExt;
try {
_Init(path, _fAccessSav, _shareSav, _secAttrsSav, _secAccessSav, _modeSav, _flagsAndAttributesSav, _seekToEndSav);
// Dispose the old handle and release the file write lock
// No need to flush the buffer as we just came off a write
if (handle != null && !handle.IsClosed) {
handle.Dispose();
}
}
catch (IOException ) {
// Should we do this only for ERROR_SHARING_VIOLATION?
//if (UnsafeNativeMethods.MakeErrorCodeFromHR(Marshal.GetHRForException(ioexc)) != InternalResources.ERROR_SHARING_VIOLATION) break;
// Possible sharing violation - ----? Let the next iteration try again
// For now revert the handle to the original one
_handle = handle;
_retentionRetryCount++;
if (_retentionRetryCount >= _retentionRetryThreshold) {
_DisableLogging();
}
#if DEBUG
throw;
#endif
}
catch (UnauthorizedAccessException ) {
// Indicative of ACL issues
_DisableLogging();
#if DEBUG
throw;
#endif
}
catch (Exception ) {
_DisableLogging();
#if DEBUG
throw;
#endif
}
}
}
break;
case LogRetentionOption.SingleFileBoundedSize:
if (lastPos >= _maxFileSize)
_DisableLogging();
break;
case LogRetentionOption.SingleFileUnboundedSize:
break;
}
}
// When we enable this class widely, we need to raise an
// event when we disable logging due to rention policy or
// error such as ACL that is preventing retention
[MethodImplAttribute(MethodImplOptions.Synchronized)]
private void _DisableLogging()
{
// Discard write buffer?
_disableLogging = true;
}
[System.Security.SecurityCritical]
private static UnsafeNativeMethods.SECURITY_ATTRIBUTES GetSecAttrs(FileShare share)
{
UnsafeNativeMethods.SECURITY_ATTRIBUTES secAttrs = null;
if ((share & FileShare.Inheritable) != 0) {
secAttrs = new UnsafeNativeMethods.SECURITY_ATTRIBUTES();
secAttrs.nLength = (int)Marshal.SizeOf(secAttrs);
secAttrs.bInheritHandle = 1;
}
return secAttrs;
}
}
}

View File

@@ -0,0 +1,40 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Classes: MemoryMappedFileAccess
** MemoryMappedFileOptions
**
** Purpose: Enums for managed MemoryMappedFiles.
**
** Date: February 7, 2007
**
===========================================================*/
using System;
namespace System.IO.MemoryMappedFiles {
// This enum maps to both the PAGE_XXX and FILE_MAP_XXX native macro definitions.
// It is used in places that check the page access of the memory mapped file. ACL
// access is controlled by MemoryMappedFileRights.
[Serializable]
public enum MemoryMappedFileAccess {
ReadWrite = 0,
Read,
Write, // Write is valid only when creating views and not when creating MemoryMappedFiles
CopyOnWrite,
ReadExecute,
ReadWriteExecute,
}
[Serializable, Flags]
public enum MemoryMappedFileOptions {
None = 0,
DelayAllocatePages = 0x4000000
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: MemoryMappedFileSecurity
**
** Purpose: Managed ACL wrapper for MemoryMappedFiles.
**
** Date: February 7, 2007
**
===========================================================*/
using System;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Permissions;
using System.Security.Principal;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
namespace System.IO.MemoryMappedFiles
{
[Flags]
public enum MemoryMappedFileRights
{
// These correspond to win32 FILE_MAP_XXX constants
// No None field - An ACE with the value 0 cannot grant nor deny.
CopyOnWrite = 0x000001,
Write = 0x000002,
Read = 0x000004,
Execute = 0x000008,
Delete = 0x010000,
ReadPermissions = 0x020000,
ChangePermissions = 0x040000,
TakeOwnership = 0x080000,
//Synchronize = Not supported by memory mapped files
ReadWrite = Read | Write,
ReadExecute = Read | Execute,
ReadWriteExecute = Read | Write | Execute,
FullControl = CopyOnWrite | Read | Write | Execute | Delete |
ReadPermissions | ChangePermissions | TakeOwnership,
AccessSystemSecurity = 0x01000000, // Allow changes to SACL
}
public class MemoryMappedFileSecurity : ObjectSecurity<MemoryMappedFileRights>
{
public MemoryMappedFileSecurity()
: base(false, ResourceType.KernelObject)
{ }
[System.Security.SecuritySafeCritical]
internal MemoryMappedFileSecurity(SafeMemoryMappedFileHandle safeHandle, AccessControlSections includeSections )
: base(false, ResourceType.KernelObject, safeHandle, includeSections)
{ }
[System.Security.SecuritySafeCritical]
internal void PersistHandle(SafeHandle handle) {
Persist(handle);
}
}
}

View File

@@ -0,0 +1,239 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: MemoryMappedView
**
** Purpose: Internal class representing MemoryMappedFile view
**
** Date: February 7, 2007
**
===========================================================*/
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Security;
using System.Threading;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
namespace System.IO.MemoryMappedFiles {
internal class MemoryMappedView : IDisposable {
private SafeMemoryMappedViewHandle m_viewHandle;
private Int64 m_pointerOffset;
private Int64 m_size;
private MemoryMappedFileAccess m_access;
// These control the retry behaviour when lock violation errors occur during Flush:
private const Int32 MaxFlushWaits = 15; // must be <=30
private const Int32 MaxFlushRetriesPerWait = 20;
[System.Security.SecurityCritical]
private unsafe MemoryMappedView(SafeMemoryMappedViewHandle viewHandle, Int64 pointerOffset,
Int64 size, MemoryMappedFileAccess access) {
m_viewHandle = viewHandle;
m_pointerOffset = pointerOffset;
m_size = size;
m_access = access;
}
internal SafeMemoryMappedViewHandle ViewHandle {
[System.Security.SecurityCritical]
get {
return m_viewHandle;
}
}
internal Int64 PointerOffset {
get {
return m_pointerOffset;
}
}
internal Int64 Size {
get {
return m_size;
}
}
internal MemoryMappedFileAccess Access {
get {
return m_access;
}
}
// Callers must demand unmanaged code first
[System.Security.SecurityCritical]
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;
}
// Flushes the changes such that they are in [....] with the FileStream bits (ones obtained
// with the win32 ReadFile and WriteFile functions). Need to call FileStream's Flush to
// flush to the disk.
// NOTE: This will flush all bytes before and after the view up until an offset that is a multiple
// of SystemPageSize.
[System.Security.SecurityCritical]
public void Flush(IntPtr capacity) {
if (m_viewHandle != null) {
unsafe {
byte* firstPagePtr = null;
RuntimeHelpers.PrepareConstrainedRegions();
try {
m_viewHandle.AcquirePointer(ref firstPagePtr);
bool success = UnsafeNativeMethods.FlushViewOfFile(firstPagePtr, capacity);
if (success)
return; // This will visit the finally block.
// It is a known issue within the NTFS transaction log system that
// causes FlushViewOfFile to intermittently fail with ERROR_LOCK_VIOLATION
// [http://bugcheck/bugs/Windows8Bugs/152862].
// As a workaround, we catch this particular error and retry the flush operation
// a few milliseconds later. If it does not work, we give it a few more tries with
// increasing intervals. Eventually, however, we need to give up. In ad-hoc tests
// this strategy successfully flushed the view after no more than 3 retries.
Int32 error = Marshal.GetLastWin32Error();
bool canRetry = (!success && error == UnsafeNativeMethods.ERROR_LOCK_VIOLATION);
for (Int32 w = 0; canRetry && w < MaxFlushWaits; w++) {
Int32 pause = (1 << w); // MaxFlushRetries should never be over 30
Thread.Sleep(pause);
for (Int32 r = 0; canRetry && r < MaxFlushRetriesPerWait; r++) {
success = UnsafeNativeMethods.FlushViewOfFile(firstPagePtr, capacity);
if (success)
return; // This will visit the finally block.
Thread.Sleep(0);
error = Marshal.GetLastWin32Error();
canRetry = (error == UnsafeNativeMethods.ERROR_LOCK_VIOLATION);
}
}
// We got too here, so there was no success:
__Error.WinIOError(error, String.Empty);
}
finally {
if (firstPagePtr != null) {
m_viewHandle.ReleasePointer();
}
}
}
}
}
[System.Security.SecurityCritical]
protected virtual void Dispose(bool disposing) {
if (m_viewHandle != null && !m_viewHandle.IsClosed) {
m_viewHandle.Dispose();
}
}
[System.Security.SecurityCritical]
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
internal bool IsClosed {
[SecuritySafeCritical]
get {
return (m_viewHandle == null || m_viewHandle.IsClosed);
}
}
}
}

View File

@@ -0,0 +1,98 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: MemoryMappedViewAccessor
**
** Purpose: View accessor for managed MemoryMappedFiles
**
** Date: February 7, 2007
**
===========================================================*/
using System;
using System.Diagnostics;
using System.Security;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;
namespace System.IO.MemoryMappedFiles {
public sealed class MemoryMappedViewAccessor : UnmanagedMemoryAccessor {
private MemoryMappedView m_view;
[System.Security.SecurityCritical]
internal MemoryMappedViewAccessor(MemoryMappedView view) {
Debug.Assert(view != null, "view is null");
m_view = view;
Initialize(m_view.ViewHandle, m_view.PointerOffset, m_view.Size, MemoryMappedFile.GetFileAccess(m_view.Access));
}
public SafeMemoryMappedViewHandle SafeMemoryMappedViewHandle {
[System.Security.SecurityCritical]
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
get {
return m_view != null ? m_view.ViewHandle : null;
}
}
public long PointerOffset
{
get
{
if (m_view == null)
{
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_ViewIsNull));
}
return m_view.PointerOffset;
}
}
[SecuritySafeCritical]
protected override void Dispose(bool disposing) {
try {
// Explicitly flush the changes. The OS will do this for us anyway, but not until after the
// MemoryMappedFile object itself is closed.
if (disposing && m_view != null && !m_view.IsClosed) {
Flush();
}
}
finally {
try {
if (m_view != null) {
m_view.Dispose();
}
}
finally {
base.Dispose(disposing);
}
}
}
// Flushes the changes such that they are in [....] with the FileStream bits (ones obtained
// with the win32 ReadFile and WriteFile functions). Need to call FileStream's Flush to
// flush to the disk.
// NOTE: This will flush all bytes before and after the view up until an offset that is a
// multiple of SystemPageSize.
[System.Security.SecurityCritical]
public void Flush() {
if (!IsOpen) {
throw new ObjectDisposedException("MemoryMappedViewAccessor", SR.GetString(SR.ObjectDisposed_ViewAccessorClosed));
}
unsafe {
if (m_view != null) {
m_view.Flush((IntPtr)Capacity);
}
}
}
}
}

View File

@@ -0,0 +1,100 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: MemoryMappedViewStream
**
** Purpose: View stream for managed MemoryMappedFiles.
**
** Date: February 7, 2007
**
===========================================================*/
using System;
using System.Diagnostics;
using System.Security;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;
namespace System.IO.MemoryMappedFiles {
public sealed class MemoryMappedViewStream : UnmanagedMemoryStream {
private MemoryMappedView m_view;
[System.Security.SecurityCritical]
internal unsafe MemoryMappedViewStream(MemoryMappedView view) {
Debug.Assert(view != null, "view is null");
m_view = view;
Initialize(m_view.ViewHandle, m_view.PointerOffset, m_view.Size, MemoryMappedFile.GetFileAccess(m_view.Access));
}
public SafeMemoryMappedViewHandle SafeMemoryMappedViewHandle {
[System.Security.SecurityCritical]
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
get {
return m_view != null ? m_view.ViewHandle : null;
}
}
public override void SetLength(long value) {
throw new NotSupportedException(SR.GetString(SR.NotSupported_MMViewStreamsFixedLength));
}
public long PointerOffset
{
get
{
if (m_view == null)
{
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_ViewIsNull));
}
return m_view.PointerOffset;
}
}
[SecuritySafeCritical]
protected override void Dispose(bool disposing) {
try {
if (disposing && m_view != null && !m_view.IsClosed) {
Flush();
}
}
finally {
try {
if (m_view != null) {
m_view.Dispose();
}
}
finally {
base.Dispose(disposing);
}
}
}
// Flushes the changes such that they are in [....] with the FileStream bits (ones obtained
// with the win32 ReadFile and WriteFile functions). Need to call FileStream's Flush to
// flush to the disk.
// NOTE: This will flush all bytes before and after the view up until an offset that is a
// multiple of SystemPageSize.
[System.Security.SecurityCritical]
public override void Flush() {
if (!CanSeek) {
__Error.StreamIsClosed();
}
unsafe {
if (m_view != null) {
m_view.Flush((IntPtr)Capacity);
}
}
}
}
}

View File

@@ -0,0 +1,44 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: Enums
**
**
** Purpose: Enums for pipe streams.
**
**
===========================================================*/
using System;
using System.Text;
namespace System.IO.Pipes {
[Serializable]
public enum PipeDirection {
In = 1,
Out = 2,
InOut = In | Out,
}
[Serializable]
public enum PipeTransmissionMode {
Byte = 0,
Message = 1,
}
[Serializable]
[Flags]
public enum PipeOptions {
None = 0x0,
WriteThrough = unchecked((int)0x80000000),
Asynchronous = unchecked((int)0x40000000), // corresponds to FILE_FLAG_OVERLAPPED
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,473 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: PipeSecurity
**
**
** Purpose: Managed ACL wrapper for Pipes.
**
**
===========================================================*/
using System;
using System.Collections;
using System.Security.AccessControl;
using System.Security.Permissions;
using System.Security.Principal;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.IO;
using System.Runtime.Versioning;
namespace System.IO.Pipes {
[Flags]
public enum PipeAccessRights {
// No None field - An ACE with the value 0 cannot grant nor deny.
ReadData = 0x000001,
WriteData = 0x000002,
// Not that all client named pipes require ReadAttributes access even if the user does not specify it.
// (This is because CreateFile slaps on the requirement before calling NTCreateFile (at least in WinXP SP2)).
ReadAttributes = 0x000080,
WriteAttributes = 0x000100,
// These aren't really needed since there is no operation that requires this access, but they are left here
// so that people can specify ACLs that others can open by specifying a PipeDirection rather than a
// PipeAccessRights (PipeDirection.In/Out maps to GENERIC_READ/WRITE access).
ReadExtendedAttributes = 0x000008,
WriteExtendedAttributes = 0x000010,
CreateNewInstance = 0x000004, // AppendData
// Again, this is not needed but it should be here so that our FullControl matches windows.
Delete = 0x010000,
ReadPermissions = 0x020000,
ChangePermissions = 0x040000,
TakeOwnership = 0x080000,
Synchronize = 0x100000,
FullControl = ReadData | WriteData | ReadAttributes | ReadExtendedAttributes |
WriteAttributes | WriteExtendedAttributes | CreateNewInstance |
Delete | ReadPermissions | ChangePermissions | TakeOwnership |
Synchronize,
Read = ReadData | ReadAttributes | ReadExtendedAttributes | ReadPermissions,
Write = WriteData | WriteAttributes | WriteExtendedAttributes, // | CreateNewInstance, For security, I really don't this CreateNewInstance belongs here.
ReadWrite = Read | Write,
// These are somewhat similar to what you get if you use PipeDirection:
//In = ReadData | ReadAttributes | ReadExtendedAttributes | ReadPermissions,
//Out = WriteData | WriteAttributes | WriteExtendedAttributes | ChangePermissions | CreateNewInstance | ReadAttributes, // NOTE: Not sure if ReadAttributes should really be here
//InOut = In | Out,
AccessSystemSecurity = 0x01000000, // Allow changes to SACL.
}
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
public sealed class PipeAccessRule : AccessRule {
#region Constructors
//
// Constructor for creating access rules for pipe objects
//
public PipeAccessRule(
String identity,
PipeAccessRights rights,
AccessControlType type)
: this(
new NTAccount(identity),
AccessMaskFromRights(rights, type),
false,
type) {
}
public PipeAccessRule(
IdentityReference identity,
PipeAccessRights rights,
AccessControlType type)
: this(
identity,
AccessMaskFromRights(rights, type),
false,
type) {
}
//
// Internal constructor to be called by public constructors
// and the access rights factory methods
//
internal PipeAccessRule(
IdentityReference identity,
int accessMask,
bool isInherited,
AccessControlType type)
: base(
identity,
accessMask,
isInherited,
InheritanceFlags.None, // these do not apply to pipes
PropagationFlags.None, // these do not apply to pipes
type) {
}
#endregion
#region Public properties
public PipeAccessRights PipeAccessRights {
get {
return RightsFromAccessMask(base.AccessMask);
}
}
#endregion
#region Access mask to rights translation
// ACL's on pipes have a SYNCHRONIZE bit, and CreateFile ALWAYS asks for it.
// So for allows, let's always include this bit, and for denies, let's never
// include this bit unless we're denying full control. This is the right
// thing for users, even if it does make the model look asymmetrical from a
// purist point of view.
internal static int AccessMaskFromRights(PipeAccessRights rights, AccessControlType controlType) {
if (rights < (PipeAccessRights)0 || rights > (PipeAccessRights.FullControl | PipeAccessRights.AccessSystemSecurity))
throw new ArgumentOutOfRangeException("rights", SR.GetString(SR.ArgumentOutOfRange_NeedValidPipeAccessRights));
if (controlType == AccessControlType.Allow) {
rights |= PipeAccessRights.Synchronize;
}
else if (controlType == AccessControlType.Deny) {
if (rights != PipeAccessRights.FullControl) {
rights &= ~PipeAccessRights.Synchronize;
}
}
return (int)rights;
}
internal static PipeAccessRights RightsFromAccessMask(int accessMask) {
return (PipeAccessRights)accessMask;
}
#endregion
}
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
public sealed class PipeAuditRule : AuditRule {
#region Constructors
public PipeAuditRule(
IdentityReference identity,
PipeAccessRights rights,
AuditFlags flags)
: this(
identity,
AccessMaskFromRights(rights),
false,
flags) {
}
public PipeAuditRule(
String identity,
PipeAccessRights rights,
AuditFlags flags)
: this(
new NTAccount(identity),
AccessMaskFromRights(rights),
false,
flags) {
}
internal PipeAuditRule(
IdentityReference identity,
int accessMask,
bool isInherited,
AuditFlags flags)
: base(
identity,
accessMask,
isInherited,
InheritanceFlags.None,
PropagationFlags.None,
flags) {
}
#endregion
#region Private methods
private static int AccessMaskFromRights(PipeAccessRights rights) {
if (rights < (PipeAccessRights)0 || rights > (PipeAccessRights.FullControl | PipeAccessRights.AccessSystemSecurity)) {
throw new ArgumentOutOfRangeException("rights", SR.GetString(SR.ArgumentOutOfRange_NeedValidPipeAccessRights));
}
return (int)rights;
}
#endregion
#region Public properties
public PipeAccessRights PipeAccessRights {
get {
return PipeAccessRule.RightsFromAccessMask(base.AccessMask);
}
}
#endregion
}
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
public class PipeSecurity : NativeObjectSecurity {
public PipeSecurity()
: base(false, ResourceType.KernelObject) { }
// Used by PipeStream.GetAccessControl
[System.Security.SecuritySafeCritical]
internal PipeSecurity(SafePipeHandle safeHandle, AccessControlSections includeSections)
: base(false, ResourceType.KernelObject, safeHandle, includeSections) { }
public void AddAccessRule(PipeAccessRule rule) {
if (rule == null)
throw new ArgumentNullException("rule");
base.AddAccessRule(rule);
}
public void SetAccessRule(PipeAccessRule rule) {
if (rule == null)
throw new ArgumentNullException("rule");
base.SetAccessRule(rule);
}
public void ResetAccessRule(PipeAccessRule rule) {
if (rule == null)
throw new ArgumentNullException("rule");
base.ResetAccessRule(rule);
}
public bool RemoveAccessRule(PipeAccessRule rule) {
if (rule == null) {
throw new ArgumentNullException("rule");
}
// If the rule to be removed matches what is there currently then
// remove it unaltered. That is, don't mask off the Synchronize bit.
AuthorizationRuleCollection rules = GetAccessRules(true, true,
rule.IdentityReference.GetType());
for (int i = 0; i < rules.Count; i++) {
PipeAccessRule fsrule = rules[i] as PipeAccessRule;
if ((fsrule != null) && (fsrule.PipeAccessRights == rule.PipeAccessRights)
&& (fsrule.IdentityReference == rule.IdentityReference)
&& (fsrule.AccessControlType == rule.AccessControlType)) {
return base.RemoveAccessRule(rule);
}
}
// It didn't exactly match any of the current rules so remove this way:
// mask off the synchronize bit (that is automatically added for Allow)
// before removing the ACL. The logic here should be same as Deny and hence
// fake a call to AccessMaskFromRights as though the ACL is for Deny
if (rule.PipeAccessRights != PipeAccessRights.FullControl) {
return base.RemoveAccessRule(new PipeAccessRule(
rule.IdentityReference,
PipeAccessRule.AccessMaskFromRights(rule.PipeAccessRights, AccessControlType.Deny),
false,
rule.AccessControlType));
}
else {
return base.RemoveAccessRule(rule);
}
}
public void RemoveAccessRuleSpecific(PipeAccessRule rule) {
if (rule == null) {
throw new ArgumentNullException("rule");
}
// If the rule to be removed matches what is there currently then
// remove it unaltered. That is, don't mask off the Synchronize bit
AuthorizationRuleCollection rules = GetAccessRules(true, true,
rule.IdentityReference.GetType());
for (int i = 0; i < rules.Count; i++) {
PipeAccessRule fsrule = rules[i] as PipeAccessRule;
if ((fsrule != null) && (fsrule.PipeAccessRights == rule.PipeAccessRights)
&& (fsrule.IdentityReference == rule.IdentityReference)
&& (fsrule.AccessControlType == rule.AccessControlType)) {
base.RemoveAccessRuleSpecific(rule);
return;
}
}
// It wasn't an exact match so try masking the sychronize bit (that is
// automatically added for Allow) before removing the ACL. The logic
// here should be same as Deny and hence fake a call to
// AccessMaskFromRights as though the ACL is for Deny
if (rule.PipeAccessRights != PipeAccessRights.FullControl) {
base.RemoveAccessRuleSpecific(new PipeAccessRule(rule.IdentityReference,
PipeAccessRule.AccessMaskFromRights(rule.PipeAccessRights, AccessControlType.Deny),
false,
rule.AccessControlType));
}
else {
base.RemoveAccessRuleSpecific(rule);
}
}
public void AddAuditRule(PipeAuditRule rule) {
base.AddAuditRule(rule);
}
public void SetAuditRule(PipeAuditRule rule) {
base.SetAuditRule(rule);
}
public bool RemoveAuditRule(PipeAuditRule rule) {
return base.RemoveAuditRule(rule);
}
public void RemoveAuditRuleAll(PipeAuditRule rule) {
base.RemoveAuditRuleAll(rule);
}
public void RemoveAuditRuleSpecific(PipeAuditRule rule) {
base.RemoveAuditRuleSpecific(rule);
}
public override AccessRule AccessRuleFactory(IdentityReference identityReference,
int accessMask, bool isInherited, InheritanceFlags inheritanceFlags,
PropagationFlags propagationFlags, AccessControlType type) {
// Throw if inheritance flags or propagation flags set. Have to include in signature
// since this is an override
if (inheritanceFlags != InheritanceFlags.None) {
throw new ArgumentException(SR.GetString(SR.Argument_NonContainerInvalidAnyFlag), "inheritanceFlags");
}
if (propagationFlags != PropagationFlags.None) {
throw new ArgumentException(SR.GetString(SR.Argument_NonContainerInvalidAnyFlag), "propagationFlags");
}
return new PipeAccessRule(
identityReference,
accessMask,
isInherited,
type);
}
public sealed override AuditRule AuditRuleFactory(
IdentityReference identityReference,
int accessMask,
bool isInherited,
InheritanceFlags inheritanceFlags,
PropagationFlags propagationFlags,
AuditFlags flags) {
// Throw if inheritance flags or propagation flags set. Have to include in signature
// since this is an override
if (inheritanceFlags != InheritanceFlags.None) {
throw new ArgumentException(SR.GetString(SR.Argument_NonContainerInvalidAnyFlag), "inheritanceFlags");
}
if (propagationFlags != PropagationFlags.None) {
throw new ArgumentException(SR.GetString(SR.Argument_NonContainerInvalidAnyFlag), "propagationFlags");
}
return new PipeAuditRule(
identityReference,
accessMask,
isInherited,
flags);
}
#region Private Methods
private AccessControlSections GetAccessControlSectionsFromChanges() {
AccessControlSections persistRules = AccessControlSections.None;
if (AccessRulesModified)
persistRules = AccessControlSections.Access;
if (AuditRulesModified)
persistRules |= AccessControlSections.Audit;
if (OwnerModified)
persistRules |= AccessControlSections.Owner;
if (GroupModified)
persistRules |= AccessControlSections.Group;
return persistRules;
}
#endregion
#region Protected Methods
// Use this in your own Persist after you have demanded any appropriate CAS permissions.
// Note that you will want your version to be internal and use a specialized Safe Handle.
[System.Security.SecurityCritical]
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
protected internal void Persist(SafeHandle handle) {
WriteLock();
try {
AccessControlSections persistRules = GetAccessControlSectionsFromChanges();
base.Persist(handle, persistRules);
OwnerModified = GroupModified = AuditRulesModified = AccessRulesModified = false;
}
finally {
WriteUnlock();
}
}
// Use this in your own Persist after you have demanded any appropriate CAS permissions.
// Note that you will want your version to be internal.
[System.Security.SecurityCritical]
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
protected internal void Persist(String name) {
WriteLock();
try {
AccessControlSections persistRules = GetAccessControlSectionsFromChanges();
base.Persist(name, persistRules);
OwnerModified = GroupModified = AuditRulesModified = AccessRulesModified = false;
}
finally {
WriteUnlock();
}
}
#endregion
#region some overrides
public override Type AccessRightType {
get {
return typeof(PipeAccessRights);
}
}
public override Type AccessRuleType {
get {
return typeof(PipeAccessRule);
}
}
public override Type AuditRuleType {
get {
return typeof(PipeAuditRule);
}
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,221 @@
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: __Error
**
**
** Purpose: Centralized error methods. Used for translating
** Win32 HRESULTs into meaningful error strings & exceptions.
**
**
===========================================================*/
using System;
using System.Globalization;
using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using UnsafeNativeMethods = Microsoft.Win32.UnsafeNativeMethods;
namespace System.IO {
// Only static data; no need to serialize
internal static class __Error {
internal static void EndOfFile() {
throw new EndOfStreamException(SR.GetString(SR.IO_EOF_ReadBeyondEOF));
}
internal static void FileNotOpen() {
throw new ObjectDisposedException(null, SR.GetString(SR.ObjectDisposed_FileClosed));
}
internal static void PipeNotOpen() {
throw new ObjectDisposedException(null, SR.GetString(SR.ObjectDisposed_PipeClosed));
}
internal static void StreamIsClosed() {
throw new ObjectDisposedException(null, SR.GetString(SR.ObjectDisposed_StreamIsClosed));
}
internal static void ReadNotSupported() {
throw new NotSupportedException(SR.GetString(SR.NotSupported_UnreadableStream));
}
internal static void SeekNotSupported() {
throw new NotSupportedException(SR.GetString(SR.NotSupported_UnseekableStream));
}
internal static void WrongAsyncResult() {
throw new ArgumentException(SR.GetString(SR.Argument_WrongAsyncResult));
}
internal static void EndReadCalledTwice() {
// Should ideally be InvalidOperationExc but we can't maintain parity with Stream and FileStream without some work
throw new ArgumentException(SR.GetString(SR.InvalidOperation_EndReadCalledMultiple));
}
internal static void EndWriteCalledTwice() {
// Should ideally be InvalidOperationExc but we can't maintain parity with Stream and FileStream without some work
throw new ArgumentException(SR.GetString(SR.InvalidOperation_EndWriteCalledMultiple));
}
internal static void EndWaitForConnectionCalledTwice() {
// Should ideally be InvalidOperationExc but we can't maitain parity with Stream and FileStream without some work
throw new ArgumentException(SR.GetString(SR.InvalidOperation_EndWaitForConnectionCalledMultiple));
}
/// <summary>
/// Given a possible fully qualified path, ensure that we have path discovery permission
/// to that path. If we do not, return just the file name. If we know it is a directory,
/// then don't return the directory name.
/// </summary>
/// <param name="path"></param>
/// <param name="isInvalidPath"></param>
/// <returns></returns>
[SecuritySafeCritical]
internal static String GetDisplayablePath(String path, bool isInvalidPath) {
if (String.IsNullOrEmpty(path)) {
return path;
}
// Is it a fully qualified path?
bool isFullyQualified = false;
if (path.Length < 2) {
return path;
}
if ((path[0] == Path.DirectorySeparatorChar) && (path[1] == Path.DirectorySeparatorChar)) {
isFullyQualified = true;
}
else if (path[1] == Path.VolumeSeparatorChar) {
isFullyQualified = true;
}
if (!isFullyQualified && !isInvalidPath) {
return path;
}
bool safeToReturn = false;
try {
if (!isInvalidPath) {
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { path }).Demand();
safeToReturn = true;
}
}
catch (SecurityException) {
}
catch (ArgumentException) {
// ? and * characters cause ArgumentException to be thrown from HasIllegalCharacters
// inside FileIOPermission.AddPathList
}
catch (NotSupportedException) {
// paths like "!Bogus\\dir:with/junk_.in it" can cause NotSupportedException to be thrown
// from Security.Util.StringExpressionSet.CanonicalizePath when ':' is found in the path
// beyond string index position 1.
}
if (!safeToReturn) {
if ((path[path.Length - 1]) == Path.DirectorySeparatorChar) {
path = SR.GetString(SR.IO_IO_NoPermissionToDirectoryName);
}
else {
path = Path.GetFileName(path);
}
}
return path;
}
[System.Security.SecurityCritical]
internal static void WinIOError() {
int errorCode = Marshal.GetLastWin32Error();
WinIOError(errorCode, String.Empty);
}
// After calling GetLastWin32Error(), it clears the last error field, so you must save the
// HResult and pass it to this method. This method will determine the appropriate
// exception to throw dependent on your error, and depending on the error, insert a string
// into the message gotten from the ResourceManager.
[System.Security.SecurityCritical]
internal static void WinIOError(int errorCode, String maybeFullPath) {
// This doesn't have to be perfect, but is a perf optimization.
bool isInvalidPath = errorCode == UnsafeNativeMethods.ERROR_INVALID_NAME || errorCode == UnsafeNativeMethods.ERROR_BAD_PATHNAME;
String str = GetDisplayablePath(maybeFullPath, isInvalidPath);
switch (errorCode) {
case UnsafeNativeMethods.ERROR_FILE_NOT_FOUND:
if (str.Length == 0) {
throw new FileNotFoundException(SR.GetString(SR.IO_FileNotFound));
}
else {
throw new FileNotFoundException(String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.IO_FileNotFound_FileName), str), str);
}
case UnsafeNativeMethods.ERROR_PATH_NOT_FOUND:
if (str.Length == 0) {
throw new DirectoryNotFoundException(SR.GetString(SR.IO_PathNotFound_NoPathName));
}
else {
throw new DirectoryNotFoundException(String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.IO_PathNotFound_Path), str));
}
case UnsafeNativeMethods.ERROR_ACCESS_DENIED:
if (str.Length == 0) {
throw new UnauthorizedAccessException(SR.GetString(SR.UnauthorizedAccess_IODenied_NoPathName));
}
else {
throw new UnauthorizedAccessException(String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.UnauthorizedAccess_IODenied_Path), str));
}
case UnsafeNativeMethods.ERROR_ALREADY_EXISTS:
if (str.Length == 0) {
goto default;
}
throw new IOException(SR.GetString(SR.IO_IO_AlreadyExists_Name, str), UnsafeNativeMethods.MakeHRFromErrorCode(errorCode));
case UnsafeNativeMethods.ERROR_FILENAME_EXCED_RANGE:
throw new PathTooLongException(SR.GetString(SR.IO_PathTooLong));
case UnsafeNativeMethods.ERROR_INVALID_DRIVE:
throw new DriveNotFoundException(String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.IO_DriveNotFound_Drive), str));
case UnsafeNativeMethods.ERROR_INVALID_PARAMETER:
throw new IOException(UnsafeNativeMethods.GetMessage(errorCode), UnsafeNativeMethods.MakeHRFromErrorCode(errorCode));
case UnsafeNativeMethods.ERROR_SHARING_VIOLATION:
if (str.Length == 0) {
throw new IOException(SR.GetString(SR.IO_IO_SharingViolation_NoFileName), UnsafeNativeMethods.MakeHRFromErrorCode(errorCode));
}
else {
throw new IOException(SR.GetString(SR.IO_IO_SharingViolation_File, str), UnsafeNativeMethods.MakeHRFromErrorCode(errorCode));
}
case UnsafeNativeMethods.ERROR_FILE_EXISTS:
if (str.Length == 0) {
goto default;
}
throw new IOException(String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.IO_IO_FileExists_Name), str), UnsafeNativeMethods.MakeHRFromErrorCode(errorCode));
case UnsafeNativeMethods.ERROR_OPERATION_ABORTED:
throw new OperationCanceledException();
default:
throw new IOException(UnsafeNativeMethods.GetMessage(errorCode), UnsafeNativeMethods.MakeHRFromErrorCode(errorCode));
}
}
internal static void WriteNotSupported() {
throw new NotSupportedException(SR.GetString(SR.NotSupported_UnwritableStream));
}
}
}