File: System\IO\__Error.cs
Project: ndp\fx\src\Core\System.Core.csproj (System.Core)
// ==++==
// 
//   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));
        }
    }
}