You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
File diff suppressed because it is too large
Load Diff
31
mcs/class/referencesource/System.Core/System/IO/Enums.cs
Normal file
31
mcs/class/referencesource/System.Core/System/IO/Enums.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
/*============================================================
|
||||
**
|
||||
** Class: Enums
|
||||
**
|
||||
**
|
||||
** Purpose: Enums shared by IO classes
|
||||
**
|
||||
**
|
||||
===========================================================*/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace System.IO {
|
||||
|
||||
#if !FEATURE_CORESYSTEM
|
||||
[Serializable]
|
||||
#endif
|
||||
public enum HandleInheritability {
|
||||
None = 0,
|
||||
Inheritable = 1,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
469
mcs/class/referencesource/System.Core/System/IO/LogStream.cs
Normal file
469
mcs/class/referencesource/System.Core/System/IO/LogStream.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
// ==++==
|
||||
//
|
||||
// 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(ref 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
|
||||
// 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 & UnsafeNativeMethods.MEM_RESERVE) != 0) || (viewSize < nativeSize)) {
|
||||
ulong allocSize = (nativeSize == 0) ? viewSize : nativeSize;
|
||||
IntPtr tempHandle = UnsafeNativeMethods.VirtualAlloc(viewHandle, (UIntPtr)allocSize, UnsafeNativeMethods.MEM_COMMIT,
|
||||
MemoryMappedFile.GetPageAccess(access));
|
||||
int lastError = Marshal.GetLastWin32Error();
|
||||
// The following is commented out for backward compatibility.
|
||||
// Previously releases failed to check for this error so introducing this check
|
||||
// could cause new/different exceptions in existing code paths.
|
||||
// if (tempHandle == IntPtr.Zero) {
|
||||
// __Error.WinIOError(lastError, String.Empty);
|
||||
// }
|
||||
|
||||
// again query the view for its new size
|
||||
viewInfo = new UnsafeNativeMethods.MEMORY_BASIC_INFORMATION();
|
||||
UnsafeNativeMethods.VirtualQuery(viewHandle, ref viewInfo, (IntPtr)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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Threading;
|
||||
using UnsafeNativeMethods = Microsoft.Win32.UnsafeNativeMethods;
|
||||
|
||||
namespace System.IO.Pipes {
|
||||
internal unsafe class IOCancellationHelper {
|
||||
private CancellationToken _cancellationToken;
|
||||
private CancellationTokenRegistration _cancellationRegistration;
|
||||
[SecurityCritical]
|
||||
private SafeHandle _handle;
|
||||
[SecurityCritical]
|
||||
private NativeOverlapped* _overlapped;
|
||||
|
||||
public IOCancellationHelper(CancellationToken cancellationToken) {
|
||||
this._cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marking that from this moment on
|
||||
/// user can cancel operation using cancellationToken
|
||||
/// </summary>
|
||||
[SecurityCritical]
|
||||
public void AllowCancellation(SafeHandle handle, NativeOverlapped* overlapped) {
|
||||
Contract.Assert(handle != null, "Handle cannot be null");
|
||||
Contract.Assert(!handle.IsInvalid, "Handle cannot be invalid");
|
||||
Contract.Assert(overlapped != null, "Overlapped cannot be null");
|
||||
Contract.Assert(this._handle == null && this._overlapped == null, "Cancellation is already allowed.");
|
||||
|
||||
if (!_cancellationToken.CanBeCanceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._handle = handle;
|
||||
this._overlapped = overlapped;
|
||||
if (this._cancellationToken.IsCancellationRequested) {
|
||||
this.Cancel();
|
||||
}
|
||||
else {
|
||||
this._cancellationRegistration = this._cancellationToken.Register(Cancel);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marking that operation is completed and
|
||||
/// from this moment cancellation is no longer possible.
|
||||
/// This MUST happen before Overlapped is freed and Handle is disposed.
|
||||
/// </summary>
|
||||
[SecurityCritical]
|
||||
public void SetOperationCompleted() {
|
||||
if (this._overlapped != null) {
|
||||
this._cancellationRegistration.Dispose();
|
||||
this._handle = null;
|
||||
this._overlapped = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void ThrowIOOperationAborted() {
|
||||
this._cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// If we didn't throw that means that this is unexpected abortion
|
||||
__Error.OperationAborted();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancellation is not guaranteed to succeed.
|
||||
/// We ignore all errors here because operation could
|
||||
/// succeed just before it was called or someone already
|
||||
/// cancelled this operation without using token which should
|
||||
/// be manually detected - when operation finishes we should
|
||||
/// compare error code to ERROR_OPERATION_ABORTED and if cancellation
|
||||
/// token was not used to cancel we will throw.
|
||||
/// </summary>
|
||||
[SecurityCritical]
|
||||
private void Cancel() {
|
||||
// Storing to locals to avoid data ----s
|
||||
SafeHandle handle = this._handle;
|
||||
NativeOverlapped* overlapped = this._overlapped;
|
||||
if (handle != null && !handle.IsInvalid && overlapped != null) {
|
||||
if (!UnsafeNativeMethods.CancelIoEx(handle, overlapped))
|
||||
{
|
||||
// This case should not have any consequences although
|
||||
// it will be easier to debug if there exists any special case
|
||||
// we are not aware of.
|
||||
int errorCode = Marshal.GetLastWin32Error();
|
||||
Debug.WriteLine("CancelIoEx finished with error code {0}.", errorCode);
|
||||
}
|
||||
SetOperationCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1479
mcs/class/referencesource/System.Core/System/IO/Pipes/Pipe.cs
Normal file
1479
mcs/class/referencesource/System.Core/System/IO/Pipes/Pipe.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
1348
mcs/class/referencesource/System.Core/System/IO/Pipes/PipeStream.cs
Normal file
1348
mcs/class/referencesource/System.Core/System/IO/Pipes/PipeStream.cs
Normal file
File diff suppressed because it is too large
Load Diff
224
mcs/class/referencesource/System.Core/System/IO/__Error.cs
Normal file
224
mcs/class/referencesource/System.Core/System/IO/__Error.cs
Normal file
@@ -0,0 +1,224 @@
|
||||
// ==++==
|
||||
//
|
||||
// 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));
|
||||
}
|
||||
|
||||
internal static void OperationAborted() {
|
||||
throw new IOException(SR.GetString(SR.IO_OperationAborted));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user