diff options
Diffstat (limited to 'src/mscorlib/corefx/Interop/Unix/Interop.IOErrors.cs')
-rw-r--r-- | src/mscorlib/corefx/Interop/Unix/Interop.IOErrors.cs | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/src/mscorlib/corefx/Interop/Unix/Interop.IOErrors.cs b/src/mscorlib/corefx/Interop/Unix/Interop.IOErrors.cs new file mode 100644 index 0000000000..e9d6ce61d6 --- /dev/null +++ b/src/mscorlib/corefx/Interop/Unix/Interop.IOErrors.cs @@ -0,0 +1,170 @@ +// 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; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; + +internal static partial class Interop +{ + private static void ThrowExceptionForIoErrno(ErrorInfo errorInfo, string path, bool isDirectory, Func<ErrorInfo, ErrorInfo> errorRewriter) + { + Debug.Assert(errorInfo.Error != Error.SUCCESS); + Debug.Assert(errorInfo.Error != Error.EINTR, "EINTR errors should be handled by the native shim and never bubble up to managed code"); + + if (errorRewriter != null) + { + errorInfo = errorRewriter(errorInfo); + } + + throw Interop.GetExceptionForIoErrno(errorInfo, path, isDirectory); + } + + internal static void CheckIo(Error error, string path = null, bool isDirectory = false, Func<ErrorInfo, ErrorInfo> errorRewriter = null) + { + if (error != Interop.Error.SUCCESS) + { + ThrowExceptionForIoErrno(error.Info(), path, isDirectory, errorRewriter); + } + } + + /// <summary> + /// Validates the result of system call that returns greater than or equal to 0 on success + /// and less than 0 on failure, with errno set to the error code. + /// If the system call failed for any reason, an exception is thrown. Otherwise, the system call succeeded. + /// </summary> + /// <param name="result">The result of the system call.</param> + /// <param name="path">The path with which this error is associated. This may be null.</param> + /// <param name="isDirectory">true if the <paramref name="path"/> is known to be a directory; otherwise, false.</param> + /// <param name="errorRewriter">Optional function to change an error code prior to processing it.</param> + /// <returns> + /// On success, returns the non-negative result long that was validated. + /// </returns> + internal static long CheckIo(long result, string path = null, bool isDirectory = false, Func<ErrorInfo, ErrorInfo> errorRewriter = null) + { + if (result < 0) + { + ThrowExceptionForIoErrno(Sys.GetLastErrorInfo(), path, isDirectory, errorRewriter); + } + + return result; + } + + /// <summary> + /// Validates the result of system call that returns greater than or equal to 0 on success + /// and less than 0 on failure, with errno set to the error code. + /// If the system call failed for any reason, an exception is thrown. Otherwise, the system call succeeded. + /// </summary> + /// <returns> + /// On success, returns the non-negative result int that was validated. + /// </returns> + internal static int CheckIo(int result, string path = null, bool isDirectory = false, Func<ErrorInfo, ErrorInfo> errorRewriter = null) + { + CheckIo((long)result, path, isDirectory, errorRewriter); + + return result; + } + + /// <summary> + /// Validates the result of system call that returns greater than or equal to 0 on success + /// and less than 0 on failure, with errno set to the error code. + /// If the system call failed for any reason, an exception is thrown. Otherwise, the system call succeeded. + /// </summary> + /// <returns> + /// On success, returns the non-negative result IntPtr that was validated. + /// </returns> + internal static IntPtr CheckIo(IntPtr result, string path = null, bool isDirectory = false, Func<ErrorInfo, ErrorInfo> errorRewriter = null) + { + CheckIo((long)result, path, isDirectory, errorRewriter); + + return result; + } + + /// <summary> + /// Validates the result of system call that returns greater than or equal to 0 on success + /// and less than 0 on failure, with errno set to the error code. + /// If the system call failed for any reason, an exception is thrown. Otherwise, the system call succeeded. + /// </summary> + /// <returns> + /// On success, returns the valid SafeFileHandle that was validated. + /// </returns> + internal static TSafeHandle CheckIo<TSafeHandle>(TSafeHandle handle, string path = null, bool isDirectory = false, Func<ErrorInfo, ErrorInfo> errorRewriter = null) + where TSafeHandle : SafeHandle + { + if (handle.IsInvalid) + { + ThrowExceptionForIoErrno(Sys.GetLastErrorInfo(), path, isDirectory, errorRewriter); + } + + return handle; + } + + /// <summary> + /// Gets an Exception to represent the supplied error info. + /// </summary> + /// <param name="error">The error info</param> + /// <param name="path">The path with which this error is associated. This may be null.</param> + /// <param name="isDirectory">true if the <paramref name="path"/> is known to be a directory; otherwise, false.</param> + /// <returns></returns> + internal static Exception GetExceptionForIoErrno(ErrorInfo errorInfo, string path = null, bool isDirectory = false) + { + // Translate the errno into a known set of exception types. For cases where multiple errnos map + // to the same exception type, include an inner exception with the details. + switch (errorInfo.Error) + { + case Error.ENOENT: + if (isDirectory) + { + return !string.IsNullOrEmpty(path) ? + new DirectoryNotFoundException(SR.Format(SR.IO_PathNotFound_Path, path)) : + new DirectoryNotFoundException(SR.IO_PathNotFound_NoPathName); + } + else + { + return !string.IsNullOrEmpty(path) ? + new FileNotFoundException(SR.Format(SR.IO_FileNotFound_FileName, path), path) : + new FileNotFoundException(SR.IO_FileNotFound); + } + + case Error.EACCES: + case Error.EBADF: + case Error.EPERM: + Exception inner = GetIOException(errorInfo); + return !string.IsNullOrEmpty(path) ? + new UnauthorizedAccessException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, path), inner) : + new UnauthorizedAccessException(SR.UnauthorizedAccess_IODenied_NoPathName, inner); + + case Error.ENAMETOOLONG: + return new PathTooLongException(SR.IO_PathTooLong); + + case Error.EWOULDBLOCK: + return !string.IsNullOrEmpty(path) ? + new IOException(SR.Format(SR.IO_SharingViolation_File, path), errorInfo.RawErrno) : + new IOException(SR.IO_SharingViolation_NoFileName, errorInfo.RawErrno); + + case Error.ECANCELED: + return new OperationCanceledException(); + + case Error.EFBIG: + return new ArgumentOutOfRangeException("value", SR.ArgumentOutOfRange_FileLengthTooBig); + + case Error.EEXIST: + if (!string.IsNullOrEmpty(path)) + { + return new IOException(SR.Format(SR.IO_FileExists_Name, path), errorInfo.RawErrno); + } + goto default; + + default: + return GetIOException(errorInfo); + } + } + + internal static Exception GetIOException(Interop.ErrorInfo errorInfo) + { + return new IOException(errorInfo.GetErrorMessage(), errorInfo.RawErrno); + } +} |