diff options
Diffstat (limited to 'src/mscorlib/corefx/System/IO')
-rw-r--r-- | src/mscorlib/corefx/System/IO/FileStream.NetStandard17.cs | 76 | ||||
-rw-r--r-- | src/mscorlib/corefx/System/IO/FileStream.Win32.cs | 76 | ||||
-rw-r--r-- | src/mscorlib/corefx/System/IO/FileStream.cs | 94 | ||||
-rw-r--r-- | src/mscorlib/corefx/System/IO/FileStreamCompletionSource.Win32.cs | 6 | ||||
-rw-r--r-- | src/mscorlib/corefx/System/IO/Path.Unix.cs | 62 | ||||
-rw-r--r-- | src/mscorlib/corefx/System/IO/Path.Windows.cs | 32 | ||||
-rw-r--r-- | src/mscorlib/corefx/System/IO/Path.cs | 33 | ||||
-rw-r--r-- | src/mscorlib/corefx/System/IO/PathHelper.Windows.cs | 245 | ||||
-rw-r--r-- | src/mscorlib/corefx/System/IO/PathInternal.CaseSensitivity.cs | 75 | ||||
-rw-r--r-- | src/mscorlib/corefx/System/IO/PathInternal.Unix.cs | 42 | ||||
-rw-r--r-- | src/mscorlib/corefx/System/IO/PathInternal.Windows.StringBuffer.cs | 18 | ||||
-rw-r--r-- | src/mscorlib/corefx/System/IO/PathInternal.Windows.cs | 124 | ||||
-rw-r--r-- | src/mscorlib/corefx/System/IO/PathInternal.cs | 58 | ||||
-rw-r--r-- | src/mscorlib/corefx/System/IO/Win32Marshal.cs | 45 |
14 files changed, 348 insertions, 638 deletions
diff --git a/src/mscorlib/corefx/System/IO/FileStream.NetStandard17.cs b/src/mscorlib/corefx/System/IO/FileStream.NetStandard17.cs deleted file mode 100644 index dc1385fbc0..0000000000 --- a/src/mscorlib/corefx/System/IO/FileStream.NetStandard17.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Win32.SafeHandles; -using System.Threading.Tasks; -using System.Diagnostics; -using System.Threading; - -namespace System.IO -{ - public partial class FileStream : Stream - { - public override IAsyncResult BeginRead(byte[] array, int offset, int numBytes, AsyncCallback callback, object state) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - if (offset < 0) - throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); - if (numBytes < 0) - throw new ArgumentOutOfRangeException(nameof(numBytes), SR.ArgumentOutOfRange_NeedNonNegNum); - if (array.Length - offset < numBytes) - throw new ArgumentException(SR.Argument_InvalidOffLen); - - if (IsClosed) throw new ObjectDisposedException(SR.ObjectDisposed_FileClosed); - if (!CanRead) throw new NotSupportedException(SR.NotSupported_UnreadableStream); - - if (!IsAsync) - return base.BeginRead(array, offset, numBytes, callback, state); - else - return TaskToApm.Begin(ReadAsyncInternal(array, offset, numBytes, CancellationToken.None), callback, state); - } - - public override IAsyncResult BeginWrite(byte[] array, int offset, int numBytes, AsyncCallback callback, object state) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - if (offset < 0) - throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); - if (numBytes < 0) - throw new ArgumentOutOfRangeException(nameof(numBytes), SR.ArgumentOutOfRange_NeedNonNegNum); - if (array.Length - offset < numBytes) - throw new ArgumentException(SR.Argument_InvalidOffLen); - - if (IsClosed) throw new ObjectDisposedException(SR.ObjectDisposed_FileClosed); - if (!CanWrite) throw new NotSupportedException(SR.NotSupported_UnwritableStream); - - if (!IsAsync) - return base.BeginWrite(array, offset, numBytes, callback, state); - else - return TaskToApm.Begin(WriteAsyncInternal(array, offset, numBytes, CancellationToken.None), callback, state); - } - - public override int EndRead(IAsyncResult asyncResult) - { - if (asyncResult == null) - throw new ArgumentNullException(nameof(asyncResult)); - - if (!IsAsync) - return base.EndRead(asyncResult); - else - return TaskToApm.End<int>(asyncResult); - } - - public override void EndWrite(IAsyncResult asyncResult) - { - if (asyncResult == null) - throw new ArgumentNullException(nameof(asyncResult)); - - if (!IsAsync) - base.EndWrite(asyncResult); - else - TaskToApm.End(asyncResult); - } - } -} diff --git a/src/mscorlib/corefx/System/IO/FileStream.Win32.cs b/src/mscorlib/corefx/System/IO/FileStream.Win32.cs index 350d948b00..683eef5e43 100644 --- a/src/mscorlib/corefx/System/IO/FileStream.Win32.cs +++ b/src/mscorlib/corefx/System/IO/FileStream.Win32.cs @@ -55,7 +55,7 @@ namespace System.IO private SafeFileHandle OpenHandle(FileMode mode, FileShare share, FileOptions options) { - Interop.mincore.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share); + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share); int fAccess = ((_access & FileAccess.Read) == FileAccess.Read ? GENERIC_READ : 0) | @@ -74,13 +74,13 @@ namespace System.IO // 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 - flagsAndAttributes |= (Interop.mincore.SecurityOptions.SECURITY_SQOS_PRESENT | Interop.mincore.SecurityOptions.SECURITY_ANONYMOUS); + flagsAndAttributes |= (Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT | Interop.Kernel32.SecurityOptions.SECURITY_ANONYMOUS); // Don't pop up a dialog for reading from an empty floppy drive - uint oldMode = Interop.mincore.SetErrorMode(Interop.mincore.SEM_FAILCRITICALERRORS); + uint oldMode = Interop.Kernel32.SetErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS); try { - SafeFileHandle fileHandle = Interop.mincore.SafeCreateFile(_path, fAccess, share, ref secAttrs, mode, flagsAndAttributes, IntPtr.Zero); + SafeFileHandle fileHandle = Interop.Kernel32.SafeCreateFile(_path, fAccess, share, ref secAttrs, mode, flagsAndAttributes, IntPtr.Zero); fileHandle.IsAsync = _useAsyncIO; if (fileHandle.IsInvalid) @@ -92,8 +92,8 @@ namespace System.IO // probably be consistent w/ every other directory. int errorCode = Marshal.GetLastWin32Error(); - if (errorCode == Interop.mincore.Errors.ERROR_PATH_NOT_FOUND && _path.Equals(Directory.InternalGetDirectoryRoot(_path))) - errorCode = Interop.mincore.Errors.ERROR_ACCESS_DENIED; + if (errorCode == Interop.Errors.ERROR_PATH_NOT_FOUND && _path.Equals(Directory.InternalGetDirectoryRoot(_path))) + errorCode = Interop.Errors.ERROR_ACCESS_DENIED; throw Win32Marshal.GetExceptionForWin32Error(errorCode, _path); } @@ -102,7 +102,7 @@ namespace System.IO } finally { - Interop.mincore.SetErrorMode(oldMode); + Interop.Kernel32.SetErrorMode(oldMode); } } @@ -112,8 +112,8 @@ namespace System.IO // constructors that take a String. Everyone else can call // CreateFile themselves then use the constructor that takes an // IntPtr. Disallows "con:", "com1:", "lpt1:", etc. - int fileType = Interop.mincore.GetFileType(_fileHandle); - if (fileType != Interop.mincore.FileTypes.FILE_TYPE_DISK) + int fileType = Interop.Kernel32.GetFileType(_fileHandle); + if (fileType != Interop.Kernel32.FileTypes.FILE_TYPE_DISK) { _fileHandle.Dispose(); throw new NotSupportedException(SR.NotSupported_FileStreamOnNonFiles); @@ -163,11 +163,11 @@ namespace System.IO private void InitFromHandle(SafeFileHandle handle) { - int handleType = Interop.mincore.GetFileType(_fileHandle); - Debug.Assert(handleType == Interop.mincore.FileTypes.FILE_TYPE_DISK || handleType == Interop.mincore.FileTypes.FILE_TYPE_PIPE || handleType == Interop.mincore.FileTypes.FILE_TYPE_CHAR, "FileStream was passed an unknown file type!"); + int handleType = Interop.Kernel32.GetFileType(_fileHandle); + Debug.Assert(handleType == Interop.Kernel32.FileTypes.FILE_TYPE_DISK || handleType == Interop.Kernel32.FileTypes.FILE_TYPE_PIPE || handleType == Interop.Kernel32.FileTypes.FILE_TYPE_CHAR, "FileStream was passed an unknown file type!"); - _canSeek = handleType == Interop.mincore.FileTypes.FILE_TYPE_DISK; - _isPipe = handleType == Interop.mincore.FileTypes.FILE_TYPE_PIPE; + _canSeek = handleType == Interop.Kernel32.FileTypes.FILE_TYPE_DISK; + _isPipe = handleType == Interop.Kernel32.FileTypes.FILE_TYPE_PIPE; // This is necessary for async IO using IO Completion ports via our // managed Threadpool API's. This calls the OS's @@ -196,7 +196,7 @@ namespace System.IO } else if (!_useAsyncIO) { - if (handleType != Interop.mincore.FileTypes.FILE_TYPE_PIPE) + if (handleType != Interop.Kernel32.FileTypes.FILE_TYPE_PIPE) VerifyHandleIsSync(); } @@ -211,13 +211,13 @@ namespace System.IO return handle.IsAsync.HasValue ? handle.IsAsync.Value : false; } - private unsafe static Interop.mincore.SECURITY_ATTRIBUTES GetSecAttrs(FileShare share) + private unsafe static Interop.Kernel32.SECURITY_ATTRIBUTES GetSecAttrs(FileShare share) { - Interop.mincore.SECURITY_ATTRIBUTES secAttrs = default(Interop.mincore.SECURITY_ATTRIBUTES); + Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = default(Interop.Kernel32.SECURITY_ATTRIBUTES); if ((share & FileShare.Inheritable) != 0) { - secAttrs = new Interop.mincore.SECURITY_ATTRIBUTES(); - secAttrs.nLength = (uint)sizeof(Interop.mincore.SECURITY_ATTRIBUTES); + secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES(); + secAttrs.nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES); secAttrs.bInheritHandle = Interop.BOOL.TRUE; } @@ -234,7 +234,7 @@ namespace System.IO // cause an app to block incorrectly, introducing a deadlock (depending // on whether a write will wake up an already-blocked thread or this // Win32FileStream's thread). - Debug.Assert(Interop.mincore.GetFileType(_fileHandle) != Interop.mincore.FileTypes.FILE_TYPE_PIPE); + Debug.Assert(Interop.Kernel32.GetFileType(_fileHandle) != Interop.Kernel32.FileTypes.FILE_TYPE_PIPE); byte* bytes = stackalloc byte[1]; int numBytesReadWritten; @@ -246,11 +246,11 @@ namespace System.IO // accidentally read synchronously from an async pipe. if ((_access & FileAccess.Read) != 0) // don't use the virtual CanRead or CanWrite, as this may be used in the ctor { - r = Interop.mincore.ReadFile(_fileHandle, bytes, 0, out numBytesReadWritten, IntPtr.Zero); + r = Interop.Kernel32.ReadFile(_fileHandle, bytes, 0, out numBytesReadWritten, IntPtr.Zero); } else if ((_access & FileAccess.Write) != 0) // don't use the virtual CanRead or CanWrite, as this may be used in the ctor { - r = Interop.mincore.WriteFile(_fileHandle, bytes, 0, out numBytesReadWritten, IntPtr.Zero); + r = Interop.Kernel32.WriteFile(_fileHandle, bytes, 0, out numBytesReadWritten, IntPtr.Zero); } if (r == 0) @@ -273,9 +273,9 @@ namespace System.IO private long GetLengthInternal() { - Interop.mincore.FILE_STANDARD_INFO info = new Interop.mincore.FILE_STANDARD_INFO(); + Interop.Kernel32.FILE_STANDARD_INFO info = new Interop.Kernel32.FILE_STANDARD_INFO(); - if (!Interop.mincore.GetFileInformationByHandleEx(_fileHandle, Interop.mincore.FILE_INFO_BY_HANDLE_CLASS.FileStandardInfo, out info, (uint)Marshal.SizeOf<Interop.mincore.FILE_STANDARD_INFO>())) + if (!Interop.Kernel32.GetFileInformationByHandleEx(_fileHandle, Interop.Kernel32.FILE_INFO_BY_HANDLE_CLASS.FileStandardInfo, out info, (uint)Marshal.SizeOf<Interop.Kernel32.FILE_STANDARD_INFO>())) throw Win32Marshal.GetExceptionForLastWin32Error(); long len = info.EndOfFile; // If we're writing near the end of the file, we must include our @@ -334,7 +334,7 @@ namespace System.IO private void FlushOSBuffer() { - if (!Interop.mincore.FlushFileBuffers(_fileHandle)) + if (!Interop.Kernel32.FlushFileBuffers(_fileHandle)) { throw Win32Marshal.GetExceptionForLastWin32Error(); } @@ -426,10 +426,10 @@ namespace System.IO VerifyOSHandlePosition(); if (_filePosition != value) SeekCore(value, SeekOrigin.Begin); - if (!Interop.mincore.SetEndOfFile(_fileHandle)) + if (!Interop.Kernel32.SetEndOfFile(_fileHandle)) { int errorCode = Marshal.GetLastWin32Error(); - if (errorCode == Interop.mincore.Errors.ERROR_INVALID_PARAMETER) + if (errorCode == Interop.Errors.ERROR_INVALID_PARAMETER) throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_FileLengthTooBig); throw Win32Marshal.GetExceptionForWin32Error(errorCode); } @@ -658,7 +658,7 @@ namespace System.IO Debug.Assert(origin >= SeekOrigin.Begin && origin <= SeekOrigin.End, "origin>=SeekOrigin.Begin && origin<=SeekOrigin.End"); long ret = 0; - if (!Interop.mincore.SetFilePointerEx(_fileHandle, offset, out ret, (uint)origin)) + if (!Interop.Kernel32.SetFilePointerEx(_fileHandle, offset, out ret, (uint)origin)) { int errorCode = GetLastWin32ErrorAndDisposeHandleIfInvalid(); throw Win32Marshal.GetExceptionForWin32Error(errorCode); @@ -1277,12 +1277,12 @@ namespace System.IO int r = 0; int numBytesRead = 0; - fixed (byte* p = bytes) + fixed (byte* p = &bytes[0]) { if (_useAsyncIO) - r = Interop.mincore.ReadFile(handle, p + offset, count, IntPtr.Zero, overlapped); + r = Interop.Kernel32.ReadFile(handle, p + offset, count, IntPtr.Zero, overlapped); else - r = Interop.mincore.ReadFile(handle, p + offset, count, out numBytesRead, IntPtr.Zero); + r = Interop.Kernel32.ReadFile(handle, p + offset, count, out numBytesRead, IntPtr.Zero); } if (r == 0) @@ -1322,12 +1322,12 @@ namespace System.IO int numBytesWritten = 0; int r = 0; - fixed (byte* p = bytes) + fixed (byte* p = &bytes[0]) { if (_useAsyncIO) - r = Interop.mincore.WriteFile(handle, p + offset, count, IntPtr.Zero, overlapped); + r = Interop.Kernel32.WriteFile(handle, p + offset, count, IntPtr.Zero, overlapped); else - r = Interop.mincore.WriteFile(handle, p + offset, count, out numBytesWritten, IntPtr.Zero); + r = Interop.Kernel32.WriteFile(handle, p + offset, count, out numBytesWritten, IntPtr.Zero); } if (r == 0) @@ -1363,7 +1363,7 @@ namespace System.IO // Note that _parent.Dispose doesn't throw so we don't need to special case. // SetHandleAsInvalid only sets _closed field to true (without // actually closing handle) so we don't need to call that as well. - if (errorCode == Interop.mincore.Errors.ERROR_INVALID_HANDLE) + if (errorCode == Interop.Errors.ERROR_INVALID_HANDLE) { _fileHandle.Dispose(); @@ -1473,7 +1473,7 @@ namespace System.IO { // Try to cancel the I/O. We ignore the return value, as cancellation is opportunistic and we // don't want to fail the operation because we couldn't cancel it. - Interop.mincore.CancelIoEx(innerAwaitable._fileStream._fileHandle, innerAwaitable._nativeOverlapped); + Interop.Kernel32.CancelIoEx(innerAwaitable._fileStream._fileHandle, innerAwaitable._nativeOverlapped); } } } @@ -1538,7 +1538,7 @@ namespace System.IO case ERROR_HANDLE_EOF: // logically success with 0 bytes read (read at end of file) Debug.Assert(readAwaitable._numBytes == 0, $"Expected 0 bytes read, got {readAwaitable._numBytes}"); break; - case Interop.mincore.Errors.ERROR_OPERATION_ABORTED: // canceled + case Interop.Errors.ERROR_OPERATION_ABORTED: // canceled throw new OperationCanceledException(cancellationToken.IsCancellationRequested ? cancellationToken : new CancellationToken(true)); default: // error throw Win32Marshal.GetExceptionForWin32Error((int)readAwaitable._errorCode); @@ -1748,7 +1748,7 @@ namespace System.IO int lengthLow = unchecked((int)(length)); int lengthHigh = unchecked((int)(length >> 32)); - if (!Interop.mincore.LockFile(_fileHandle, positionLow, positionHigh, lengthLow, lengthHigh)) + if (!Interop.Kernel32.LockFile(_fileHandle, positionLow, positionHigh, lengthLow, lengthHigh)) { throw Win32Marshal.GetExceptionForLastWin32Error(); } @@ -1761,7 +1761,7 @@ namespace System.IO int lengthLow = unchecked((int)(length)); int lengthHigh = unchecked((int)(length >> 32)); - if (!Interop.mincore.UnlockFile(_fileHandle, positionLow, positionHigh, lengthLow, lengthHigh)) + if (!Interop.Kernel32.UnlockFile(_fileHandle, positionLow, positionHigh, lengthLow, lengthHigh)) { throw Win32Marshal.GetExceptionForLastWin32Error(); } diff --git a/src/mscorlib/corefx/System/IO/FileStream.cs b/src/mscorlib/corefx/System/IO/FileStream.cs index 398f5a6162..7db8518435 100644 --- a/src/mscorlib/corefx/System/IO/FileStream.cs +++ b/src/mscorlib/corefx/System/IO/FileStream.cs @@ -139,20 +139,6 @@ namespace System.IO this(path, mode, access, share, bufferSize, useAsync ? FileOptions.Asynchronous : FileOptions.None) { } - internal FileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, string msgPath, bool bFromProxy) - : this(path, mode, access, share, bufferSize, options, msgPath, bFromProxy, useLongPath: false) - { - } - - internal FileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, string msgPath, bool bFromProxy, bool useLongPath) - : this(path, mode, access, share, bufferSize, options) - { - // msgPath is the path that is handed back to untrusted code, CoreCLR is always full trust - // bFromProxy is also related to asserting rights for limited trust and also can be ignored - // useLongPath was used to get around the legacy MaxPath check, this is no longer applicable as everything supports long paths - // checkHost is also related to limited trust scenarios - } - public FileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options) { if (path == null) @@ -225,24 +211,6 @@ namespace System.IO return handle.IsAsync.HasValue ? handle.IsAsync.Value : false; } - // InternalOpen, InternalCreate, and InternalAppend: - // Factory methods for FileStream used by File, FileInfo, and ReadLinesIterator - // Specifies default access and sharing options for FileStreams created by those classes - internal static FileStream InternalOpen(string path, int bufferSize = DefaultBufferSize, bool useAsync = DefaultIsAsync) - { - return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, useAsync); - } - - internal static FileStream InternalCreate(string path, int bufferSize = DefaultBufferSize, bool useAsync = DefaultIsAsync) - { - return new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, bufferSize, useAsync); - } - - internal static FileStream InternalAppend(string path, int bufferSize = DefaultBufferSize, bool useAsync = DefaultIsAsync) - { - return new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read, bufferSize, useAsync); - } - [Obsolete("This property has been deprecated. Please use FileStream's SafeFileHandle property instead. http://go.microsoft.com/fwlink/?linkid=14202")] public virtual IntPtr Handle { get { return SafeFileHandle.DangerousGetHandle(); } } @@ -650,5 +618,67 @@ namespace System.IO // on Dispose(false) call. Dispose(false); } + + public override IAsyncResult BeginRead(byte[] array, int offset, int numBytes, AsyncCallback callback, object state) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (offset < 0) + throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); + if (numBytes < 0) + throw new ArgumentOutOfRangeException(nameof(numBytes), SR.ArgumentOutOfRange_NeedNonNegNum); + if (array.Length - offset < numBytes) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + if (IsClosed) throw new ObjectDisposedException(SR.ObjectDisposed_FileClosed); + if (!CanRead) throw new NotSupportedException(SR.NotSupported_UnreadableStream); + + if (!IsAsync) + return base.BeginRead(array, offset, numBytes, callback, state); + else + return TaskToApm.Begin(ReadAsyncInternal(array, offset, numBytes, CancellationToken.None), callback, state); + } + + public override IAsyncResult BeginWrite(byte[] array, int offset, int numBytes, AsyncCallback callback, object state) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (offset < 0) + throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum); + if (numBytes < 0) + throw new ArgumentOutOfRangeException(nameof(numBytes), SR.ArgumentOutOfRange_NeedNonNegNum); + if (array.Length - offset < numBytes) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + if (IsClosed) throw new ObjectDisposedException(SR.ObjectDisposed_FileClosed); + if (!CanWrite) throw new NotSupportedException(SR.NotSupported_UnwritableStream); + + if (!IsAsync) + return base.BeginWrite(array, offset, numBytes, callback, state); + else + return TaskToApm.Begin(WriteAsyncInternal(array, offset, numBytes, CancellationToken.None), callback, state); + } + + public override int EndRead(IAsyncResult asyncResult) + { + if (asyncResult == null) + throw new ArgumentNullException(nameof(asyncResult)); + + if (!IsAsync) + return base.EndRead(asyncResult); + else + return TaskToApm.End<int>(asyncResult); + } + + public override void EndWrite(IAsyncResult asyncResult) + { + if (asyncResult == null) + throw new ArgumentNullException(nameof(asyncResult)); + + if (!IsAsync) + base.EndWrite(asyncResult); + else + TaskToApm.End(asyncResult); + } } } diff --git a/src/mscorlib/corefx/System/IO/FileStreamCompletionSource.Win32.cs b/src/mscorlib/corefx/System/IO/FileStreamCompletionSource.Win32.cs index 532dbb0615..159e416e63 100644 --- a/src/mscorlib/corefx/System/IO/FileStreamCompletionSource.Win32.cs +++ b/src/mscorlib/corefx/System/IO/FileStreamCompletionSource.Win32.cs @@ -178,7 +178,7 @@ namespace System.IO if (result == ResultError) { int errorCode = unchecked((int)(packedResult & uint.MaxValue)); - if (errorCode == Interop.mincore.Errors.ERROR_OPERATION_ABORTED) + if (errorCode == Interop.Errors.ERROR_OPERATION_ABORTED) { TrySetCanceled(_cancellationToken.IsCancellationRequested ? _cancellationToken : new CancellationToken(true)); } @@ -204,13 +204,13 @@ namespace System.IO // If the handle is still valid, attempt to cancel the IO if (!completionSource._stream._fileHandle.IsInvalid && - !Interop.mincore.CancelIoEx(completionSource._stream._fileHandle, completionSource._overlapped)) + !Interop.Kernel32.CancelIoEx(completionSource._stream._fileHandle, completionSource._overlapped)) { int errorCode = Marshal.GetLastWin32Error(); // ERROR_NOT_FOUND is returned if CancelIoEx cannot find the request to cancel. // This probably means that the IO operation has completed. - if (errorCode != Interop.mincore.Errors.ERROR_NOT_FOUND) + if (errorCode != Interop.Errors.ERROR_NOT_FOUND) { throw Win32Marshal.GetExceptionForWin32Error(errorCode); } diff --git a/src/mscorlib/corefx/System/IO/Path.Unix.cs b/src/mscorlib/corefx/System/IO/Path.Unix.cs index 2dd1907007..c566fa0066 100644 --- a/src/mscorlib/corefx/System/IO/Path.Unix.cs +++ b/src/mscorlib/corefx/System/IO/Path.Unix.cs @@ -10,16 +10,11 @@ namespace System.IO { public static partial class Path { - public static readonly char DirectorySeparatorChar = '/'; - public static readonly char VolumeSeparatorChar = '/'; - public static readonly char PathSeparator = ':'; - - private const string DirectorySeparatorCharAsString = "/"; - public static char[] GetInvalidFileNameChars() => new char[] { '\0', '/' }; - internal static readonly int MaxPath = Interop.Sys.MaxPath; - private static readonly int MaxLongPath = MaxPath; + public static char[] GetInvalidPathChars() => new char[] { '\0' }; + + internal static int MaxPath => Interop.Sys.MaxPath; private static readonly bool s_isMac = Interop.Sys.GetUnixName() == "OSX"; @@ -47,12 +42,12 @@ namespace System.IO Debug.Assert(collapsedString.Length < path.Length || collapsedString.ToString() == path, "Either we've removed characters, or the string should be unmodified from the input path."); - if (collapsedString.Length > MaxPath) + if (collapsedString.Length > Interop.Sys.MaxPath) { throw new PathTooLongException(SR.IO_PathTooLong); } - string result = collapsedString.Length == 0 ? DirectorySeparatorCharAsString : collapsedString; + string result = collapsedString.Length == 0 ? PathInternal.DirectorySeparatorCharAsString : collapsedString; return result; } @@ -125,15 +120,15 @@ namespace System.IO } } - if (++componentCharCount > PathInternal.MaxComponentLength) + if (++componentCharCount > Interop.Sys.MaxName) { throw new PathTooLongException(SR.IO_PathTooLong); } // Normalize the directory separator if needed - if (c != Path.DirectorySeparatorChar && c == Path.AltDirectorySeparatorChar) + if (c != PathInternal.DirectorySeparatorChar && c == PathInternal.AltDirectorySeparatorChar) { - c = Path.DirectorySeparatorChar; + c = PathInternal.DirectorySeparatorChar; flippedSeparator = true; } @@ -169,7 +164,7 @@ namespace System.IO return string.IsNullOrEmpty(path) ? DefaultTempPath : PathInternal.IsDirectorySeparator(path[path.Length - 1]) ? path : - path + DirectorySeparatorChar; + path + PathInternal.DirectorySeparatorChar; } public static string GetTempFileName() @@ -197,58 +192,23 @@ namespace System.IO return false; PathInternal.CheckInvalidPathChars(path); - return path.Length > 0 && path[0] == DirectorySeparatorChar; + return path.Length > 0 && path[0] == PathInternal.DirectorySeparatorChar; } public static string GetPathRoot(string path) { if (path == null) return null; - return IsPathRooted(path) ? DirectorySeparatorCharAsString : String.Empty; + return IsPathRooted(path) ? PathInternal.DirectorySeparatorCharAsString : String.Empty; } private static unsafe void GetCryptoRandomBytes(byte* bytes, int byteCount) { -#if FEATURE_CORECLR // We want to avoid dependencies on the Crypto library when compiling in CoreCLR. This // will use the existing PAL implementation. byte[] buffer = new byte[KeyLength]; Microsoft.Win32.Win32Native.Random(bStrong: true, buffer: buffer, length: KeyLength); Runtime.InteropServices.Marshal.Copy(buffer, 0, (IntPtr)bytes, KeyLength); -#else - if (s_isMac) - { - GetCryptoRandomBytesApple(bytes, byteCount); - } - else - { - GetCryptoRandomBytesOpenSsl(bytes, byteCount); - } -#endif - } - -#if !FEATURE_CORECLR - private static unsafe void GetCryptoRandomBytesApple(byte* bytes, int byteCount) - { - Debug.Assert(bytes != null); - Debug.Assert(byteCount >= 0); - - if (Interop.CommonCrypto.CCRandomGenerateBytes(bytes, byteCount) != 0) - { - throw new InvalidOperationException(SR.InvalidOperation_Cryptography); - } - } - - private static unsafe void GetCryptoRandomBytesOpenSsl(byte* bytes, int byteCount) - { - Debug.Assert(bytes != null); - Debug.Assert(byteCount >= 0); - - if (!Interop.Crypto.GetRandomBytes(bytes, byteCount)) - { - throw new InvalidOperationException(SR.InvalidOperation_Cryptography); - } } -#endif /// <summary>Gets whether the system is case-sensitive.</summary> internal static bool IsCaseSensitive { get { return !s_isMac; } } diff --git a/src/mscorlib/corefx/System/IO/Path.Windows.cs b/src/mscorlib/corefx/System/IO/Path.Windows.cs index b597efc54e..ce867efd2c 100644 --- a/src/mscorlib/corefx/System/IO/Path.Windows.cs +++ b/src/mscorlib/corefx/System/IO/Path.Windows.cs @@ -9,14 +9,8 @@ namespace System.IO { public static partial class Path { - public static readonly char DirectorySeparatorChar = '\\'; - public static readonly char VolumeSeparatorChar = ':'; - public static readonly char PathSeparator = ';'; - - private const string DirectorySeparatorCharAsString = "\\"; - public static char[] GetInvalidFileNameChars() => new char[] - { + { '\"', '<', '>', '|', '\0', (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10, (char)11, (char)12, (char)13, (char)14, (char)15, (char)16, (char)17, (char)18, (char)19, (char)20, @@ -24,10 +18,18 @@ namespace System.IO (char)31, ':', '*', '?', '\\', '/' }; + public static char[] GetInvalidPathChars() => new char[] + { + '|', '\0', + (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10, + (char)11, (char)12, (char)13, (char)14, (char)15, (char)16, (char)17, (char)18, (char)19, (char)20, + (char)21, (char)22, (char)23, (char)24, (char)25, (char)26, (char)27, (char)28, (char)29, (char)30, + (char)31 + }; + // The max total path is 260, and the max individual component length is 255. // For example, D:\<256 char file name> isn't legal, even though it's under 260 chars. - internal static readonly int MaxPath = 260; - internal static readonly int MaxLongPath = short.MaxValue; + internal const int MaxPath = 260; // Expands the given path to a fully qualified path. public static string GetFullPath(string path) @@ -64,9 +66,9 @@ namespace System.IO // Move past the colon startIndex += 2; - if ((path.Length > 0 && path[0] == VolumeSeparatorChar) - || (path.Length >= startIndex && path[startIndex - 1] == VolumeSeparatorChar && !PathInternal.IsValidDriveChar(path[startIndex - 2])) - || (path.Length > startIndex && path.IndexOf(VolumeSeparatorChar, startIndex) != -1)) + if ((path.Length > 0 && path[0] == PathInternal.VolumeSeparatorChar) + || (path.Length >= startIndex && path[startIndex - 1] == PathInternal.VolumeSeparatorChar && !PathInternal.IsValidDriveChar(path[startIndex - 2])) + || (path.Length > startIndex && path.IndexOf(PathInternal.VolumeSeparatorChar, startIndex) != -1)) { throw new NotSupportedException(SR.Argument_PathFormatNotSupported); } @@ -92,7 +94,7 @@ namespace System.IO public static string GetTempPath() { StringBuilder sb = StringBuilderCache.Acquire(MaxPath); - uint r = Interop.mincore.GetTempPathW(MaxPath, sb); + uint r = Interop.Kernel32.GetTempPathW(MaxPath, sb); if (r == 0) throw Win32Marshal.GetExceptionForLastWin32Error(); return GetFullPath(StringBuilderCache.GetStringAndRelease(sb)); @@ -105,7 +107,7 @@ namespace System.IO string path = GetTempPath(); StringBuilder sb = StringBuilderCache.Acquire(MaxPath); - uint r = Interop.mincore.GetTempFileNameW(path, "tmp", 0, sb); + uint r = Interop.Kernel32.GetTempFileNameW(path, "tmp", 0, sb); if (r == 0) throw Win32Marshal.GetExceptionForLastWin32Error(); return StringBuilderCache.GetStringAndRelease(sb); @@ -121,7 +123,7 @@ namespace System.IO int length = path.Length; if ((length >= 1 && PathInternal.IsDirectorySeparator(path[0])) || - (length >= 2 && path[1] == VolumeSeparatorChar)) + (length >= 2 && path[1] == PathInternal.VolumeSeparatorChar)) return true; } return false; diff --git a/src/mscorlib/corefx/System/IO/Path.cs b/src/mscorlib/corefx/System/IO/Path.cs index 3b1ba6b07d..77b213968b 100644 --- a/src/mscorlib/corefx/System/IO/Path.cs +++ b/src/mscorlib/corefx/System/IO/Path.cs @@ -13,10 +13,12 @@ namespace System.IO // but they will handle most string operations. public static partial class Path { - // Platform specific alternate directory separator character. - // There is only one directory separator char on Unix, which is the same - // as the alternate separator on Windows, so same definition is used for both. - public static readonly char AltDirectorySeparatorChar = '/'; + // Public static readonly variant of the separators. The Path implementation itself is using + // internal const variant of the separators for better performance. + public static readonly char DirectorySeparatorChar = PathInternal.DirectorySeparatorChar; + public static readonly char AltDirectorySeparatorChar = PathInternal.AltDirectorySeparatorChar; + public static readonly char VolumeSeparatorChar = PathInternal.VolumeSeparatorChar; + public static readonly char PathSeparator = PathInternal.PathSeparator; // For generating random file names // 8 random bytes provides 12 chars in our encoding for the 8.3 name. @@ -90,11 +92,6 @@ namespace System.IO return null; } - public static char[] GetInvalidPathChars() - { - return PathInternal.GetInvalidPathChars(); - } - // Returns the extension of the given path. The returned value includes the // period (".") character of the extension except when you have a terminal period when you get string.Empty, such as ".exe" or // ".cpp". The returned value is null if the given path is @@ -290,7 +287,7 @@ namespace System.IO char ch = finalPath[finalPath.Length - 1]; if (!PathInternal.IsDirectoryOrVolumeSeparator(ch)) { - finalPath.Append(DirectorySeparatorChar); + finalPath.Append(PathInternal.DirectorySeparatorChar); } finalPath.Append(paths[i]); @@ -314,7 +311,7 @@ namespace System.IO char ch = path1[path1.Length - 1]; return PathInternal.IsDirectoryOrVolumeSeparator(ch) ? path1 + path2 : - path1 + DirectorySeparatorCharAsString + path2; + path1 + PathInternal.DirectorySeparatorCharAsString + path2; } private static string CombineNoChecks(string path1, string path2, string path3) @@ -340,11 +337,11 @@ namespace System.IO } else if (hasSep1) { - return path1 + path2 + DirectorySeparatorCharAsString + path3; + return path1 + path2 + PathInternal.DirectorySeparatorCharAsString + path3; } else if (hasSep2) { - return path1 + DirectorySeparatorCharAsString + path2 + path3; + return path1 + PathInternal.DirectorySeparatorCharAsString + path2 + path3; } else { @@ -352,9 +349,9 @@ namespace System.IO // a params string[]. Instead, try to use a cached StringBuilder. StringBuilder sb = StringBuilderCache.Acquire(path1.Length + path2.Length + path3.Length + 2); sb.Append(path1) - .Append(DirectorySeparatorChar) + .Append(PathInternal.DirectorySeparatorChar) .Append(path2) - .Append(DirectorySeparatorChar) + .Append(PathInternal.DirectorySeparatorChar) .Append(path3); return StringBuilderCache.GetStringAndRelease(sb); } @@ -396,19 +393,19 @@ namespace System.IO sb.Append(path1); if (!hasSep1) { - sb.Append(DirectorySeparatorChar); + sb.Append(PathInternal.DirectorySeparatorChar); } sb.Append(path2); if (!hasSep2) { - sb.Append(DirectorySeparatorChar); + sb.Append(PathInternal.DirectorySeparatorChar); } sb.Append(path3); if (!hasSep3) { - sb.Append(DirectorySeparatorChar); + sb.Append(PathInternal.DirectorySeparatorChar); } sb.Append(path4); diff --git a/src/mscorlib/corefx/System/IO/PathHelper.Windows.cs b/src/mscorlib/corefx/System/IO/PathHelper.Windows.cs index 4c2cdff45e..e2ead93185 100644 --- a/src/mscorlib/corefx/System/IO/PathHelper.Windows.cs +++ b/src/mscorlib/corefx/System/IO/PathHelper.Windows.cs @@ -11,7 +11,7 @@ namespace System.IO /// <summary> /// Wrapper to help with path normalization. /// </summary> - unsafe internal class PathHelper + internal class PathHelper { // Can't be over 8.3 and be a short name private const int MaxShortName = 12; @@ -19,9 +19,6 @@ namespace System.IO private const char LastAnsi = (char)255; private const char Delete = (char)127; - [ThreadStatic] - private static StringBuffer t_fullPathBuffer; - /// <summary> /// Normalize the given path. /// </summary> @@ -44,10 +41,11 @@ namespace System.IO internal static string Normalize(string path, bool checkInvalidCharacters, bool expandShortPaths) { // Get the full path - StringBuffer fullPath = t_fullPathBuffer ?? (t_fullPathBuffer = new StringBuffer(PathInternal.MaxShortPath)); + StringBuffer fullPath = new StringBuffer(PathInternal.MaxShortPath); + try { - GetFullPathName(path, fullPath); + GetFullPathName(path, ref fullPath); // Trim whitespace off the end of the string. Win32 normalization trims only U+0020. fullPath.TrimEnd(PathInternal.s_trimEndChars); @@ -82,17 +80,16 @@ namespace System.IO // path that contains UNC or to see if the path was doing something like \\.\GLOBALROOT\Device\Mup\, // \\.\GLOBAL\UNC\, \\.\GLOBALROOT\GLOBAL??\UNC\, etc. bool specialPath = fullPath.Length > 1 && fullPath[0] == '\\' && fullPath[1] == '\\'; - bool isDevice = PathInternal.IsDevice(fullPath); + bool isDevice = PathInternal.IsDevice(ref fullPath); bool possibleBadUnc = specialPath && !isDevice; - uint index = specialPath ? 2u : 0; - uint lastSeparator = specialPath ? 1u : 0; - uint segmentLength; - char* start = fullPath.CharPointer; + int index = specialPath ? 2 : 0; + int lastSeparator = specialPath ? 1 : 0; + int segmentLength; char current; while (index < fullPath.Length) { - current = start[index]; + current = fullPath[index]; // Try to skip deeper analysis. '?' and higher are valid/ignorable except for '\', '|', and '~' if (current < '?' || current == '\\' || current == '|' || current == '~') @@ -111,7 +108,7 @@ namespace System.IO break; case '\\': segmentLength = index - lastSeparator - 1; - if (segmentLength > (uint)PathInternal.MaxComponentLength) + if (segmentLength > PathInternal.MaxComponentLength) throw new PathTooLongException(SR.IO_PathTooLong + fullPath.ToString()); lastSeparator = index; @@ -151,7 +148,7 @@ namespace System.IO throw new ArgumentException(SR.Arg_PathIllegalUNC); segmentLength = fullPath.Length - lastSeparator - 1; - if (segmentLength > (uint)PathInternal.MaxComponentLength) + if (segmentLength > PathInternal.MaxComponentLength) throw new PathTooLongException(SR.IO_PathTooLong); if (foundTilde && segmentLength <= MaxShortName) @@ -161,11 +158,11 @@ namespace System.IO // this is how we've always done this. This expansion is costly so we'll continue to let other short paths slide. if (expandShortPaths && possibleShortPath) { - return TryExpandShortFileName(fullPath, originalPath: path); + return TryExpandShortFileName(ref fullPath, originalPath: path); } else { - if (fullPath.Length == (uint)path.Length && fullPath.StartsWith(path)) + if (fullPath.Length == path.Length && fullPath.StartsWith(path)) { // If we have the exact same string we were passed in, don't bother to allocate another string from the StringBuilder. return path; @@ -184,12 +181,12 @@ namespace System.IO } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool IsDosUnc(StringBuffer buffer) + private static bool IsDosUnc(ref StringBuffer buffer) { - return !PathInternal.IsDevice(buffer) && buffer.Length > 1 && buffer[0] == '\\' && buffer[1] == '\\'; + return !PathInternal.IsDevice(ref buffer) && buffer.Length > 1 && buffer[0] == '\\' && buffer[1] == '\\'; } - private static void GetFullPathName(string path, StringBuffer fullPath) + private static unsafe void GetFullPathName(string path, ref StringBuffer fullPath) { // If the string starts with an extended prefix we would need to remove it from the path before we call GetFullPathName as // it doesn't root extended paths correctly. We don't currently resolve extended paths, so we'll just assert here. @@ -201,10 +198,10 @@ namespace System.IO fixed (char* pathStart = path) { uint result = 0; - while ((result = Interop.mincore.GetFullPathNameW(pathStart + startIndex, fullPath.CharCapacity, fullPath.GetHandle(), IntPtr.Zero)) > fullPath.CharCapacity) + while ((result = Interop.Kernel32.GetFullPathNameW(pathStart + startIndex, (uint)fullPath.Capacity, fullPath.UnderlyingArray, IntPtr.Zero)) > fullPath.Capacity) { - // Reported size (which does not include the null) is greater than the buffer size. Increase the capacity. - fullPath.EnsureCharCapacity(result); + // Reported size is greater than the buffer size. Increase the capacity. + fullPath.EnsureCapacity(checked((int)result)); } if (result == 0) @@ -212,23 +209,23 @@ namespace System.IO // Failure, get the error and throw int errorCode = Marshal.GetLastWin32Error(); if (errorCode == 0) - errorCode = Interop.mincore.Errors.ERROR_BAD_PATHNAME; + errorCode = Interop.Errors.ERROR_BAD_PATHNAME; throw Win32Marshal.GetExceptionForWin32Error(errorCode, path); } - fullPath.Length = result; + fullPath.Length = checked((int)result); } } - private static uint GetInputBuffer(StringBuffer content, bool isDosUnc, out StringBuffer buffer) + private static int GetInputBuffer(ref StringBuffer content, bool isDosUnc, ref StringBuffer buffer) { - uint length = content.Length; + int length = content.Length; length += isDosUnc - ? (uint)PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength + ? PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength : PathInternal.DevicePrefixLength; - buffer = new StringBuffer(length); + buffer.EnsureCapacity(length + 1); if (isDosUnc) { @@ -238,28 +235,28 @@ namespace System.IO // Copy the source buffer over after the existing UNC prefix content.CopyTo( bufferIndex: PathInternal.UncPrefixLength, - destination: buffer, + destination: ref buffer, destinationIndex: PathInternal.UncExtendedPrefixLength, count: content.Length - PathInternal.UncPrefixLength); // Return the prefix difference - return (uint)PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength; + return PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength; } else { - uint prefixSize = (uint)PathInternal.ExtendedPathPrefix.Length; + int prefixSize = PathInternal.ExtendedPathPrefix.Length; buffer.CopyFrom(bufferIndex: 0, source: PathInternal.ExtendedPathPrefix); - content.CopyTo(bufferIndex: 0, destination: buffer, destinationIndex: prefixSize, count: content.Length); + content.CopyTo(bufferIndex: 0, destination: ref buffer, destinationIndex: prefixSize, count: content.Length); return prefixSize; } } - private static string TryExpandShortFileName(StringBuffer outputBuffer, string originalPath) + private static string TryExpandShortFileName(ref StringBuffer outputBuffer, string originalPath) { // We guarantee we'll expand short names for paths that only partially exist. As such, we need to find the part of the path that actually does exist. To // avoid allocating like crazy we'll create only one input array and modify the contents with embedded nulls. - Debug.Assert(!PathInternal.IsPartiallyQualified(outputBuffer), "should have resolved by now"); + Debug.Assert(!PathInternal.IsPartiallyQualified(ref outputBuffer), "should have resolved by now"); // We'll have one of a few cases by now (the normalized path will have already: // @@ -271,119 +268,131 @@ namespace System.IO // // Note that we will never get \??\ here as GetFullPathName() does not recognize \??\ and will return it as C:\??\ (or whatever the current drive is). - uint rootLength = PathInternal.GetRootLength(outputBuffer); - bool isDevice = PathInternal.IsDevice(outputBuffer); + int rootLength = PathInternal.GetRootLength(ref outputBuffer); + bool isDevice = PathInternal.IsDevice(ref outputBuffer); - StringBuffer inputBuffer = null; - bool isDosUnc = false; - uint rootDifference = 0; - bool wasDotDevice = false; - - // Add the extended prefix before expanding to allow growth over MAX_PATH - if (isDevice) + StringBuffer inputBuffer = new StringBuffer(0); + try { - // We have one of the following (\\?\ or \\.\) - inputBuffer = new StringBuffer(); - inputBuffer.Append(outputBuffer); + bool isDosUnc = false; + int rootDifference = 0; + bool wasDotDevice = false; - if (outputBuffer[2] == '.') + // Add the extended prefix before expanding to allow growth over MAX_PATH + if (isDevice) { - wasDotDevice = true; - inputBuffer[2] = '?'; + // We have one of the following (\\?\ or \\.\) + inputBuffer.Append(ref outputBuffer); + + if (outputBuffer[2] == '.') + { + wasDotDevice = true; + inputBuffer[2] = '?'; + } + } + else + { + isDosUnc = IsDosUnc(ref outputBuffer); + rootDifference = GetInputBuffer(ref outputBuffer, isDosUnc, ref inputBuffer); } - } - else - { - isDosUnc = IsDosUnc(outputBuffer); - rootDifference = GetInputBuffer(outputBuffer, isDosUnc, out inputBuffer); - } - rootLength += rootDifference; - uint inputLength = inputBuffer.Length; + rootLength += rootDifference; + int inputLength = inputBuffer.Length; - bool success = false; - uint foundIndex = inputBuffer.Length - 1; + bool success = false; + int foundIndex = inputBuffer.Length - 1; - while (!success) - { - uint result = Interop.mincore.GetLongPathNameW(inputBuffer.GetHandle(), outputBuffer.GetHandle(), outputBuffer.CharCapacity); + while (!success) + { + uint result = Interop.Kernel32.GetLongPathNameW(inputBuffer.UnderlyingArray, outputBuffer.UnderlyingArray, (uint)outputBuffer.Capacity); - // Replace any temporary null we added - if (inputBuffer[foundIndex] == '\0') inputBuffer[foundIndex] = '\\'; + // Replace any temporary null we added + if (inputBuffer[foundIndex] == '\0') inputBuffer[foundIndex] = '\\'; - if (result == 0) - { - // Look to see if we couldn't find the file - int error = Marshal.GetLastWin32Error(); - if (error != Interop.mincore.Errors.ERROR_FILE_NOT_FOUND && error != Interop.mincore.Errors.ERROR_PATH_NOT_FOUND) + if (result == 0) { - // Some other failure, give up - break; - } + // Look to see if we couldn't find the file + int error = Marshal.GetLastWin32Error(); + if (error != Interop.Errors.ERROR_FILE_NOT_FOUND && error != Interop.Errors.ERROR_PATH_NOT_FOUND) + { + // Some other failure, give up + break; + } - // We couldn't find the path at the given index, start looking further back in the string. - foundIndex--; + // We couldn't find the path at the given index, start looking further back in the string. + foundIndex--; - for (; foundIndex > rootLength && inputBuffer[foundIndex] != '\\'; foundIndex--) ; - if (foundIndex == rootLength) + for (; foundIndex > rootLength && inputBuffer[foundIndex] != '\\'; foundIndex--) ; + if (foundIndex == rootLength) + { + // Can't trim the path back any further + break; + } + else + { + // Temporarily set a null in the string to get Windows to look further up the path + inputBuffer[foundIndex] = '\0'; + } + } + else if (result > outputBuffer.Capacity) { - // Can't trim the path back any further - break; + // Not enough space. The result count for this API does not include the null terminator. + outputBuffer.EnsureCapacity(checked((int)result)); + result = Interop.Kernel32.GetLongPathNameW(inputBuffer.UnderlyingArray, outputBuffer.UnderlyingArray, (uint)outputBuffer.Capacity); } else { - // Temporarily set a null in the string to get Windows to look further up the path - inputBuffer[foundIndex] = '\0'; + // Found the path + success = true; + outputBuffer.Length = checked((int)result); + if (foundIndex < inputLength - 1) + { + // It was a partial find, put the non-existent part of the path back + outputBuffer.Append(ref inputBuffer, foundIndex, inputBuffer.Length - foundIndex); + } } } - else if (result > outputBuffer.CharCapacity) + + // Strip out the prefix and return the string + ref StringBuffer bufferToUse = ref Choose(success, ref outputBuffer, ref inputBuffer); + + // Switch back from \\?\ to \\.\ if necessary + if (wasDotDevice) + bufferToUse[2] = '.'; + + string returnValue = null; + + int newLength = (int)(bufferToUse.Length - rootDifference); + if (isDosUnc) { - // Not enough space. The result count for this API does not include the null terminator. - outputBuffer.EnsureCharCapacity(result); - result = Interop.mincore.GetLongPathNameW(inputBuffer.GetHandle(), outputBuffer.GetHandle(), outputBuffer.CharCapacity); + // Need to go from \\?\UNC\ to \\?\UN\\ + bufferToUse[PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength] = '\\'; + } + + // We now need to strip out any added characters at the front of the string + if (bufferToUse.SubstringEquals(originalPath, rootDifference, newLength)) + { + // Use the original path to avoid allocating + returnValue = originalPath; } else { - // Found the path - success = true; - outputBuffer.Length = result; - if (foundIndex < inputLength - 1) - { - // It was a partial find, put the non-existent part of the path back - outputBuffer.Append(inputBuffer, foundIndex, inputBuffer.Length - foundIndex); - } + returnValue = bufferToUse.Substring(rootDifference, newLength); } - } - // Strip out the prefix and return the string - StringBuffer bufferToUse = success ? outputBuffer : inputBuffer; - - // Switch back from \\?\ to \\.\ if necessary - if (wasDotDevice) - bufferToUse[2] = '.'; - - string returnValue = null; - - int newLength = (int)(bufferToUse.Length - rootDifference); - if (isDosUnc) - { - // Need to go from \\?\UNC\ to \\?\UN\\ - bufferToUse[PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength] = '\\'; - } - - // We now need to strip out any added characters at the front of the string - if (bufferToUse.SubstringEquals(originalPath, rootDifference, newLength)) - { - // Use the original path to avoid allocating - returnValue = originalPath; + return returnValue; } - else + finally { - returnValue = bufferToUse.Substring(rootDifference, newLength); + inputBuffer.Free(); } + } - inputBuffer.Dispose(); - return returnValue; + // Helper method to workaround lack of operator ? support for ref values + private static ref StringBuffer Choose(bool condition, ref StringBuffer s1, ref StringBuffer s2) + { + if (condition) return ref s1; + else return ref s2; } } } diff --git a/src/mscorlib/corefx/System/IO/PathInternal.CaseSensitivity.cs b/src/mscorlib/corefx/System/IO/PathInternal.CaseSensitivity.cs deleted file mode 100644 index bea2df93b9..0000000000 --- a/src/mscorlib/corefx/System/IO/PathInternal.CaseSensitivity.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; - -namespace System.IO -{ - /// <summary>Contains internal path helpers that are shared between many projects.</summary> - internal static partial class PathInternal - { - private enum Tristate : byte - { - NotInitialized, - True, - False, - } - - private static Tristate s_isCaseSensitive = Tristate.NotInitialized; - - /// <summary>Returns a comparison that can be used to compare file and directory names for equality.</summary> - internal static StringComparison StringComparison - { - get - { - return IsCaseSensitive ? - StringComparison.Ordinal : - StringComparison.OrdinalIgnoreCase; - } - } - - /// <summary>Gets whether the system is case-sensitive.</summary> - internal static bool IsCaseSensitive - { - get - { - // This must be lazily initialized as there are dependencies on PathInternal's static constructor - // being fully initialized. (GetIsCaseSensitive() calls GetFullPath() which needs to use PathInternal) - if (s_isCaseSensitive == Tristate.NotInitialized) - s_isCaseSensitive = GetIsCaseSensitive() ? Tristate.True : Tristate.False; - - return s_isCaseSensitive == Tristate.True; - } - } - - /// <summary> - /// Determines whether the file system is case sensitive. - /// </summary> - /// <remarks> - /// Ideally we'd use something like pathconf with _PC_CASE_SENSITIVE, but that is non-portable, - /// not supported on Windows or Linux, etc. For now, this function creates a tmp file with capital letters - /// and then tests for its existence with lower-case letters. This could return invalid results in corner - /// cases where, for example, different file systems are mounted with differing sensitivities. - /// </remarks> - private static bool GetIsCaseSensitive() - { - try - { - string pathWithUpperCase = Path.Combine(Path.GetTempPath(), "CASESENSITIVETEST" + Guid.NewGuid().ToString("N")); - using (new FileStream(pathWithUpperCase, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None, 0x1000, FileOptions.DeleteOnClose)) - { - string lowerCased = pathWithUpperCase.ToLowerInvariant(); - return !File.Exists(lowerCased); - } - } - catch (Exception exc) - { - // In case something goes terribly wrong, we don't want to fail just because - // of a casing test, so we assume case-insensitive-but-preserving. - Debug.Fail("Casing test failed: " + exc); - return false; - } - } - } -} diff --git a/src/mscorlib/corefx/System/IO/PathInternal.Unix.cs b/src/mscorlib/corefx/System/IO/PathInternal.Unix.cs index 6c39f99556..08dc1d0251 100644 --- a/src/mscorlib/corefx/System/IO/PathInternal.Unix.cs +++ b/src/mscorlib/corefx/System/IO/PathInternal.Unix.cs @@ -10,11 +10,15 @@ namespace System.IO /// <summary>Contains internal path helpers that are shared between many projects.</summary> internal static partial class PathInternal { + internal const char DirectorySeparatorChar = '/'; + internal const char AltDirectorySeparatorChar = '/'; + internal const char VolumeSeparatorChar = '/'; + internal const char PathSeparator = ':'; + + internal const string DirectorySeparatorCharAsString = "/"; + // There is only one invalid path character in Unix private const char InvalidPathChar = '\0'; - internal static char[] GetInvalidPathChars() => new char[] { InvalidPathChar }; - - internal static readonly int MaxComponentLength = Interop.Sys.MaxName; internal const string ParentDirectoryPrefix = @"../"; @@ -34,24 +38,8 @@ namespace System.IO { // The alternate directory separator char is the same as the directory separator, // so we only need to check one. - Debug.Assert(Path.DirectorySeparatorChar == Path.AltDirectorySeparatorChar); - return c == Path.DirectorySeparatorChar; - } - - /// <summary> - /// Returns true if the path is too long - /// </summary> - internal static bool IsPathTooLong(string fullPath) - { - return fullPath.Length >= Interop.Sys.MaxPath; - } - - /// <summary> - /// Returns true if the directory is too long - /// </summary> - internal static bool IsDirectoryTooLong(string fullPath) - { - return fullPath.Length >= Interop.Sys.MaxPath; + Debug.Assert(DirectorySeparatorChar == AltDirectorySeparatorChar); + return c == DirectorySeparatorChar; } /// <summary> @@ -101,15 +89,9 @@ namespace System.IO { // The directory separator, volume separator, and the alternate directory // separator should be the same on Unix, so we only need to check one. - Debug.Assert(Path.DirectorySeparatorChar == Path.AltDirectorySeparatorChar); - Debug.Assert(Path.DirectorySeparatorChar == Path.VolumeSeparatorChar); - return ch == Path.DirectorySeparatorChar; - } - - internal static bool HasInvalidVolumeSeparator(string path) - { - // This is only ever true for Windows - return false; + Debug.Assert(DirectorySeparatorChar == AltDirectorySeparatorChar); + Debug.Assert(DirectorySeparatorChar == VolumeSeparatorChar); + return ch == DirectorySeparatorChar; } internal static bool IsPartiallyQualified(string path) diff --git a/src/mscorlib/corefx/System/IO/PathInternal.Windows.StringBuffer.cs b/src/mscorlib/corefx/System/IO/PathInternal.Windows.StringBuffer.cs index fec2218844..84953df37b 100644 --- a/src/mscorlib/corefx/System/IO/PathInternal.Windows.StringBuffer.cs +++ b/src/mscorlib/corefx/System/IO/PathInternal.Windows.StringBuffer.cs @@ -13,7 +13,7 @@ namespace System.IO /// <summary> /// Returns true if the path uses the extended syntax (\\?\) /// </summary> - internal static bool IsExtended(StringBuffer path) + internal static bool IsExtended(ref StringBuffer path) { // While paths like "//?/C:/" will work, they're treated the same as "\\.\" paths. // Skipping of normalization will *only* occur if back slashes ('\') are used. @@ -27,20 +27,24 @@ namespace System.IO /// <summary> /// Gets the length of the root of the path (drive, share, etc.). /// </summary> - internal unsafe static uint GetRootLength(StringBuffer path) + internal unsafe static int GetRootLength(ref StringBuffer path) { if (path.Length == 0) return 0; - return GetRootLength(path.CharPointer, path.Length); + + fixed (char* value = path.UnderlyingArray) + { + return GetRootLength(value, path.Length); + } } /// <summary> /// Returns true if the path uses any of the DOS device path syntaxes. ("\\.\", "\\?\", or "\??\") /// </summary> - internal static bool IsDevice(StringBuffer path) + internal static bool IsDevice(ref StringBuffer path) { // If the path begins with any two separators is will be recognized and normalized and prepped with // "\??\" for internal usage correctly. "\??\" is recognized and handled, "/??/" is not. - return IsExtended(path) + return IsExtended(ref path) || ( path.Length >= DevicePrefixLength @@ -63,7 +67,7 @@ namespace System.IO /// for C: (rooted, but relative). "C:\a" is rooted and not relative (the current directory /// will not be used to modify the path). /// </remarks> - internal static bool IsPartiallyQualified(StringBuffer path) + internal static bool IsPartiallyQualified(ref StringBuffer path) { if (path.Length < 2) { @@ -82,7 +86,7 @@ namespace System.IO // The only way to specify a fixed path that doesn't begin with two slashes // is the drive, colon, slash format- i.e. C:\ return !((path.Length >= 3) - && (path[1] == Path.VolumeSeparatorChar) + && (path[1] == VolumeSeparatorChar) && IsDirectorySeparator(path[2])); } } diff --git a/src/mscorlib/corefx/System/IO/PathInternal.Windows.cs b/src/mscorlib/corefx/System/IO/PathInternal.Windows.cs index bd7f1eae41..0ec9b30f99 100644 --- a/src/mscorlib/corefx/System/IO/PathInternal.Windows.cs +++ b/src/mscorlib/corefx/System/IO/PathInternal.Windows.cs @@ -40,6 +40,13 @@ namespace System.IO // Local and Global MS-DOS Device Names // https://msdn.microsoft.com/en-us/library/windows/hardware/ff554302.aspx + internal const char DirectorySeparatorChar = '\\'; + internal const char AltDirectorySeparatorChar = '/'; + internal const char VolumeSeparatorChar = ':'; + internal const char PathSeparator = ';'; + + internal const string DirectorySeparatorCharAsString = "\\"; + internal const string ExtendedPathPrefix = @"\\?\"; internal const string UncPathPrefix = @"\\"; internal const string UncExtendedPrefixToInsert = @"?\UNC\"; @@ -58,22 +65,6 @@ namespace System.IO internal const int UncExtendedPrefixLength = 8; internal const int MaxComponentLength = 255; - internal static char[] GetInvalidPathChars() => new char[] - { - '|', '\0', - (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10, - (char)11, (char)12, (char)13, (char)14, (char)15, (char)16, (char)17, (char)18, (char)19, (char)20, - (char)21, (char)22, (char)23, (char)24, (char)25, (char)26, (char)27, (char)28, (char)29, (char)30, - (char)31 - }; - - // [MS - FSA] 2.1.4.4 Algorithm for Determining if a FileName Is in an Expression - // https://msdn.microsoft.com/en-us/library/ff469270.aspx - private static readonly char[] s_wildcardChars = - { - '\"', '<', '>', '*', '?' - }; - /// <summary> /// Returns true if the given character is a valid drive letter /// </summary> @@ -83,24 +74,6 @@ namespace System.IO } /// <summary> - /// Returns true if the path is too long - /// </summary> - internal static bool IsPathTooLong(string fullPath) - { - // We'll never know precisely what will fail as paths get changed internally in Windows and - // may grow to exceed MaxLongPath. - return fullPath.Length >= MaxLongPath; - } - - /// <summary> - /// Returns true if the directory is too long - /// </summary> - internal static bool IsDirectoryTooLong(string fullPath) - { - return IsPathTooLong(fullPath); - } - - /// <summary> /// Adds the extended path prefix (\\?\) if not already a device path, IF the path is not relative, /// AND the path is more than 259 characters. (> MAX_PATH + null) /// </summary> @@ -193,10 +166,12 @@ namespace System.IO for (int i = 0; i < path.Length; i++) { char c = path[i]; - - if (c <= '\u001f' || c == '|') + if (c <= '|') // fast path for common case - '|' is highest illegal character { - return true; + if (c <= '\u001f' || c == '|') + { + return true; + } } } @@ -206,13 +181,24 @@ namespace System.IO /// <summary> /// Check for known wildcard characters. '*' and '?' are the most common ones. /// </summary> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal unsafe static bool HasWildCardCharacters(string path) + internal static bool HasWildCardCharacters(string path) { // Question mark is part of dos device syntax so we have to skip if we are int startIndex = IsDevice(path) ? ExtendedPathPrefix.Length : 0; - return path.IndexOfAny(s_wildcardChars, startIndex) >= 0; + // [MS - FSA] 2.1.4.4 Algorithm for Determining if a FileName Is in an Expression + // https://msdn.microsoft.com/en-us/library/ff469270.aspx + for (int i = startIndex; i < path.Length; i++) + { + char c = path[i]; + if (c <= '?') // fast path for common case - '?' is highest wildcard character + { + if (c == '\"' || c == '<' || c == '>' || c == '*' || c == '?') + return true; + } + } + + return false; } /// <summary> @@ -222,15 +208,15 @@ namespace System.IO { fixed(char* value = path) { - return (int)GetRootLength(value, (uint)path.Length); + return GetRootLength(value, path.Length); } } - private unsafe static uint GetRootLength(char* path, uint pathLength) + private unsafe static int GetRootLength(char* path, int pathLength) { - uint i = 0; - uint volumeSeparatorLength = 2; // Length to the colon "C:" - uint uncRootLength = 2; // Length to the start of the server name "\\" + int i = 0; + int volumeSeparatorLength = 2; // Length to the colon "C:" + int uncRootLength = 2; // Length to the start of the server name "\\" bool extendedSyntax = StartsWithOrdinal(path, pathLength, ExtendedPathPrefix); bool extendedUncSyntax = StartsWithOrdinal(path, pathLength, UncExtendedPathPrefix); @@ -240,12 +226,12 @@ namespace System.IO if (extendedUncSyntax) { // "\\" -> "\\?\UNC\" - uncRootLength = (uint)UncExtendedPathPrefix.Length; + uncRootLength = UncExtendedPathPrefix.Length; } else { // "C:" -> "\\?\C:" - volumeSeparatorLength += (uint)ExtendedPathPrefix.Length; + volumeSeparatorLength += ExtendedPathPrefix.Length; } } @@ -263,7 +249,7 @@ namespace System.IO while (i < pathLength && (!IsDirectorySeparator(path[i]) || --n > 0)) i++; } } - else if (pathLength >= volumeSeparatorLength && path[volumeSeparatorLength - 1] == Path.VolumeSeparatorChar) + else if (pathLength >= volumeSeparatorLength && path[volumeSeparatorLength - 1] == VolumeSeparatorChar) { // Path is at least longer than where we expect a colon, and has a colon (\\?\A:, A:) // If the colon is followed by a directory separator, move past it @@ -273,9 +259,9 @@ namespace System.IO return i; } - private unsafe static bool StartsWithOrdinal(char* source, uint sourceLength, string value) + private unsafe static bool StartsWithOrdinal(char* source, int sourceLength, string value) { - if (sourceLength < (uint)value.Length) return false; + if (sourceLength < value.Length) return false; for (int i = 0; i < value.Length; i++) { if (value[i] != source[i]) return false; @@ -314,7 +300,7 @@ namespace System.IO // The only way to specify a fixed path that doesn't begin with two slashes // is the drive, colon, slash format- i.e. C:\ return !((path.Length >= 3) - && (path[1] == Path.VolumeSeparatorChar) + && (path[1] == VolumeSeparatorChar) && IsDirectorySeparator(path[2]) // To match old behavior we'll check the drive character for validity as the path is technically // not qualified if you don't have a valid drive. "=:\" is the "=" file's default data stream. @@ -350,7 +336,7 @@ namespace System.IO [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool IsDirectorySeparator(char c) { - return c == Path.DirectorySeparatorChar || c == Path.AltDirectorySeparatorChar; + return c == DirectorySeparatorChar || c == AltDirectorySeparatorChar; } /// <summary> @@ -401,7 +387,7 @@ namespace System.IO { current = path[i]; if (IsDirectorySeparator(current) - && (current != Path.DirectorySeparatorChar + && (current != DirectorySeparatorChar // Check for sequential separators past the first position (we need to keep initial two for UNC/extended) || (i > 0 && i + 1 < path.Length && IsDirectorySeparator(path[i + 1])))) { @@ -418,7 +404,7 @@ namespace System.IO if (IsDirectorySeparator(path[start])) { start++; - builder.Append(Path.DirectorySeparatorChar); + builder.Append(DirectorySeparatorChar); } for (int i = start; i < path.Length; i++) @@ -435,7 +421,7 @@ namespace System.IO } // Ensure it is the primary separator - current = Path.DirectorySeparatorChar; + current = DirectorySeparatorChar; } builder.Append(current); @@ -450,33 +436,7 @@ namespace System.IO /// <param name="ch">The character to test.</param> internal static bool IsDirectoryOrVolumeSeparator(char ch) { - return IsDirectorySeparator(ch) || Path.VolumeSeparatorChar == ch; - } - - /// <summary> - /// Validates volume separator only occurs as C: or \\?\C:. This logic is meant to filter out Alternate Data Streams. - /// </summary> - /// <returns>True if the path has an invalid volume separator.</returns> - internal static bool HasInvalidVolumeSeparator(string path) - { - // Toss out paths with colons that aren't a valid drive specifier. - // Cannot start with a colon and can only be of the form "C:" or "\\?\C:". - // (Note that we used to explicitly check "http:" and "file:"- these are caught by this check now.) - - // We don't care about skipping starting space for extended paths. Assume no knowledge of extended paths if we're forcing old path behavior. - int startIndex = IsExtended(path) ? ExtendedPathPrefix.Length : PathStartSkip(path); - - // If we start with a colon - if ((path.Length > startIndex && path[startIndex] == Path.VolumeSeparatorChar) - // Or have an invalid drive letter and colon - || (path.Length >= startIndex + 2 && path[startIndex + 1] == Path.VolumeSeparatorChar && !IsValidDriveChar(path[startIndex])) - // Or have any colons beyond the drive colon - || (path.Length > startIndex + 2 && path.IndexOf(Path.VolumeSeparatorChar, startIndex + 2) != -1)) - { - return true; - } - - return false; + return IsDirectorySeparator(ch) || VolumeSeparatorChar == ch; } } } diff --git a/src/mscorlib/corefx/System/IO/PathInternal.cs b/src/mscorlib/corefx/System/IO/PathInternal.cs index ee67680df5..6b4c3b2d30 100644 --- a/src/mscorlib/corefx/System/IO/PathInternal.cs +++ b/src/mscorlib/corefx/System/IO/PathInternal.cs @@ -40,64 +40,6 @@ namespace System.IO if (HasIllegalCharacters(path)) throw new ArgumentException(SR.Argument_InvalidPathChars, nameof(path)); } - - - /// <summary> - /// Returns true if the given StringBuilder starts with the given value. - /// </summary> - /// <param name="value">The string to compare against the start of the StringBuilder.</param> - internal static bool StartsWithOrdinal(this StringBuilder builder, string value) - { - if (value == null || builder.Length < value.Length) - return false; - - for (int i = 0; i < value.Length; i++) - { - if (builder[i] != value[i]) return false; - } - return true; - } - - /// <summary> - /// Returns true if the given string starts with the given value. - /// </summary> - /// <param name="value">The string to compare against the start of the source string.</param> - internal static bool StartsWithOrdinal(this string source, string value) - { - if (value == null || source.Length < value.Length) - return false; - - return source.StartsWith(value, StringComparison.Ordinal); - } - - /// <summary> - /// Trims the specified characters from the end of the StringBuilder. - /// </summary> - internal static StringBuilder TrimEnd(this StringBuilder builder, params char[] trimChars) - { - if (trimChars == null || trimChars.Length == 0) - return builder; - - int end = builder.Length - 1; - - for (; end >= 0; end--) - { - int i = 0; - char ch = builder[end]; - for (; i < trimChars.Length; i++) - { - if (trimChars[i] == ch) break; - } - if (i == trimChars.Length) - { - // Not a trim char - break; - } - } - - builder.Length = end + 1; - return builder; - } /// <summary> /// Returns the start index of the filename diff --git a/src/mscorlib/corefx/System/IO/Win32Marshal.cs b/src/mscorlib/corefx/System/IO/Win32Marshal.cs index b4dfa04468..ef76c27010 100644 --- a/src/mscorlib/corefx/System/IO/Win32Marshal.cs +++ b/src/mscorlib/corefx/System/IO/Win32Marshal.cs @@ -23,16 +23,6 @@ namespace System.IO } /// <summary> - /// Converts, resetting it, the last Win32 error into a corresponding <see cref="Exception"/> object, optionally - /// including the specified path in the error message. - /// </summary> - internal static Exception GetExceptionForLastWin32Error(string path) - { - int errorCode = Marshal.GetLastWin32Error(); - return GetExceptionForWin32Error(errorCode, path); - } - - /// <summary> /// Converts the specified Win32 error into a corresponding <see cref="Exception"/> object. /// </summary> internal static Exception GetExceptionForWin32Error(int errorCode) @@ -48,49 +38,49 @@ namespace System.IO { switch (errorCode) { - case Interop.mincore.Errors.ERROR_FILE_NOT_FOUND: + case Interop.Errors.ERROR_FILE_NOT_FOUND: if (path.Length == 0) return new FileNotFoundException(SR.IO_FileNotFound); else return new FileNotFoundException(SR.Format(SR.IO_FileNotFound_FileName, path), path); - case Interop.mincore.Errors.ERROR_PATH_NOT_FOUND: + case Interop.Errors.ERROR_PATH_NOT_FOUND: if (path.Length == 0) return new DirectoryNotFoundException(SR.IO_PathNotFound_NoPathName); else return new DirectoryNotFoundException(SR.Format(SR.IO_PathNotFound_Path, path)); - case Interop.mincore.Errors.ERROR_ACCESS_DENIED: + case Interop.Errors.ERROR_ACCESS_DENIED: if (path.Length == 0) return new UnauthorizedAccessException(SR.UnauthorizedAccess_IODenied_NoPathName); else return new UnauthorizedAccessException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, path)); - case Interop.mincore.Errors.ERROR_ALREADY_EXISTS: + case Interop.Errors.ERROR_ALREADY_EXISTS: if (path.Length == 0) goto default; return new IOException(SR.Format(SR.IO_AlreadyExists_Name, path), MakeHRFromErrorCode(errorCode)); - case Interop.mincore.Errors.ERROR_FILENAME_EXCED_RANGE: + case Interop.Errors.ERROR_FILENAME_EXCED_RANGE: return new PathTooLongException(SR.IO_PathTooLong); - case Interop.mincore.Errors.ERROR_INVALID_PARAMETER: + case Interop.Errors.ERROR_INVALID_PARAMETER: return new IOException(GetMessage(errorCode), MakeHRFromErrorCode(errorCode)); - case Interop.mincore.Errors.ERROR_SHARING_VIOLATION: + case Interop.Errors.ERROR_SHARING_VIOLATION: if (path.Length == 0) return new IOException(SR.IO_SharingViolation_NoFileName, MakeHRFromErrorCode(errorCode)); else return new IOException(SR.Format(SR.IO_SharingViolation_File, path), MakeHRFromErrorCode(errorCode)); - case Interop.mincore.Errors.ERROR_FILE_EXISTS: + case Interop.Errors.ERROR_FILE_EXISTS: if (path.Length == 0) goto default; return new IOException(SR.Format(SR.IO_FileExists_Name, path), MakeHRFromErrorCode(errorCode)); - case Interop.mincore.Errors.ERROR_OPERATION_ABORTED: + case Interop.Errors.ERROR_OPERATION_ABORTED: return new OperationCanceledException(); default: @@ -109,26 +99,11 @@ namespace System.IO } /// <summary> - /// Returns a Win32 error code for the specified HRESULT if it came from FACILITY_WIN32 - /// If not, returns the HRESULT unchanged - /// </summary> - internal static int TryMakeWin32ErrorCodeFromHR(int hr) - { - if ((0xFFFF0000 & hr) == 0x80070000) - { - // Win32 error, Win32Marshal.GetExceptionForWin32Error expects the Win32 format - hr &= 0x0000FFFF; - } - - return hr; - } - - /// <summary> /// Returns a string message for the specified Win32 error code. /// </summary> internal static string GetMessage(int errorCode) { - return Interop.mincore.GetMessage(errorCode); + return Interop.Kernel32.GetMessage(errorCode); } } } |