Moving BSTR conv to native code in SecureStringToBSTR.
[mono.git] / mcs / class / referencesource / mscorlib / system / io / __error.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 /*============================================================
7 **
8 ** Class:  __Error
9 ** 
10 ** <OWNER>[....]</OWNER>
11 **
12 **
13 ** Purpose: Centralized error methods for the IO package.  
14 ** Mostly useful for translating Win32 HRESULTs into meaningful
15 ** error strings & exceptions.
16 **
17 **
18 ===========================================================*/
19
20 using System;
21 using System.Runtime.InteropServices;
22 using Win32Native = Microsoft.Win32.Win32Native;
23 using System.Text;
24 using System.Globalization;
25 using System.Security;
26 using System.Security.Permissions;
27 using System.Diagnostics.Contracts;
28
29 namespace System.IO {
30     [Pure]
31     internal static class __Error
32     {
33         internal static void EndOfFile() {
34             throw new EndOfStreamException(Environment.GetResourceString("IO.EOF_ReadBeyondEOF"));
35         }
36
37         internal static void FileNotOpen() {
38             throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_FileClosed"));
39         }
40         
41         internal static void StreamIsClosed() {
42             throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_StreamClosed"));
43         }
44     
45         internal static void MemoryStreamNotExpandable() {
46             throw new NotSupportedException(Environment.GetResourceString("NotSupported_MemStreamNotExpandable"));
47         }
48     
49         internal static void ReaderClosed() {
50             throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_ReaderClosed"));
51         }
52
53         internal static void ReadNotSupported() {
54             throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnreadableStream"));
55         }
56     
57         internal static void SeekNotSupported() {
58             throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnseekableStream"));
59         }
60
61         internal static void WrongAsyncResult() {
62             throw new ArgumentException(Environment.GetResourceString("Arg_WrongAsyncResult"));
63         }
64
65         internal static void EndReadCalledTwice() {
66             // Should ideally be InvalidOperationExc but we can't maitain parity with Stream and FileStream without some work
67             throw new ArgumentException(Environment.GetResourceString("InvalidOperation_EndReadCalledMultiple"));
68         }
69
70         internal static void EndWriteCalledTwice() {
71             // Should ideally be InvalidOperationExc but we can't maintain parity with Stream and FileStream without some work
72             throw new ArgumentException(Environment.GetResourceString("InvalidOperation_EndWriteCalledMultiple"));
73         }
74
75         // Given a possible fully qualified path, ensure that we have path
76         // discovery permission to that path.  If we do not, return just the 
77         // file name.  If we know it is a directory, then don't return the 
78         // directory name.
79         [System.Security.SecurityCritical]  // auto-generated
80         internal static String GetDisplayablePath(String path, bool isInvalidPath)
81         {
82             
83             if (String.IsNullOrEmpty(path))
84                 return String.Empty;
85
86             // Is it a fully qualified path?
87             bool isFullyQualified = false;
88             if (path.Length < 2)
89                 return path;
90             if (Path.IsDirectorySeparator(path[0]) && Path.IsDirectorySeparator(path[1]))
91                 isFullyQualified = true;
92             else if (path[1] == Path.VolumeSeparatorChar) {
93                 isFullyQualified = true;
94             }
95
96             if (!isFullyQualified && !isInvalidPath)
97                 return path;
98
99 #if FEATURE_MONO_CAS
100             bool safeToReturn = false;
101             try {
102                 if (!isInvalidPath) {
103 #if !FEATURE_CORECLR
104                     new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { path }, false, false).Demand();
105 #endif
106                     safeToReturn = true;
107                 }
108             }
109             catch (SecurityException) {
110             }
111             catch (ArgumentException) {
112                 // ? and * characters cause ArgumentException to be thrown from HasIllegalCharacters
113                 // inside FileIOPermission.AddPathList
114             }
115             catch (NotSupportedException) {
116                 // paths like "!Bogus\\dir:with/junk_.in it" can cause NotSupportedException to be thrown
117                 // from Security.Util.StringExpressionSet.CanonicalizePath when ':' is found in the path
118                 // beyond string index position 1.  
119             }
120 #else
121             bool safeToReturn = !isInvalidPath;
122 #endif // FEATURE_MONO_CAS
123             if (!safeToReturn) {
124                 if (Path.IsDirectorySeparator(path[path.Length - 1]))
125                     path = Environment.GetResourceString("IO.IO_NoPermissionToDirectoryName");
126                 else
127                     path = Path.GetFileName(path);
128             }
129
130             return path;
131         }
132 #if !MONO
133         [System.Security.SecuritySafeCritical]  // auto-generated
134         internal static void WinIOError() {
135             int errorCode = Marshal.GetLastWin32Error();
136             WinIOError(errorCode, String.Empty);
137         }
138 #endif
139         // After calling GetLastWin32Error(), it clears the last error field,
140         // so you must save the HResult and pass it to this method.  This method
141         // will determine the appropriate exception to throw dependent on your 
142         // error, and depending on the error, insert a string into the message 
143         // gotten from the ResourceManager.
144         [System.Security.SecurityCritical]  // auto-generated
145         internal static void WinIOError(int errorCode, String maybeFullPath) {
146             // This doesn't have to be perfect, but is a perf optimization.
147             bool isInvalidPath = errorCode == Win32Native.ERROR_INVALID_NAME || errorCode == Win32Native.ERROR_BAD_PATHNAME;
148             String str = GetDisplayablePath(maybeFullPath, isInvalidPath);
149
150             switch (errorCode) {
151             case Win32Native.ERROR_FILE_NOT_FOUND:
152                 if (str.Length == 0)
153                     throw new FileNotFoundException(Environment.GetResourceString("IO.FileNotFound"));
154                 else
155                     throw new FileNotFoundException(Environment.GetResourceString("IO.FileNotFound_FileName", str), str);
156                 
157             case Win32Native.ERROR_PATH_NOT_FOUND:
158                 if (str.Length == 0)
159                     throw new DirectoryNotFoundException(Environment.GetResourceString("IO.PathNotFound_NoPathName"));
160                 else
161                     throw new DirectoryNotFoundException(Environment.GetResourceString("IO.PathNotFound_Path", str));
162
163             case Win32Native.ERROR_ACCESS_DENIED:
164                 if (str.Length == 0)
165                     throw new UnauthorizedAccessException(Environment.GetResourceString("UnauthorizedAccess_IODenied_NoPathName"));
166                 else
167                     throw new UnauthorizedAccessException(Environment.GetResourceString("UnauthorizedAccess_IODenied_Path", str));
168
169             case Win32Native.ERROR_ALREADY_EXISTS:
170                 if (str.Length == 0)
171                     goto default;
172                 throw new IOException(Environment.GetResourceString("IO.IO_AlreadyExists_Name", str), Win32Native.MakeHRFromErrorCode(errorCode), maybeFullPath);
173
174             case Win32Native.ERROR_FILENAME_EXCED_RANGE:
175                 throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
176
177             case Win32Native.ERROR_INVALID_DRIVE:
178                 throw new DriveNotFoundException(Environment.GetResourceString("IO.DriveNotFound_Drive", str));
179
180             case Win32Native.ERROR_INVALID_PARAMETER:
181                 throw new IOException(Win32Native.GetMessage(errorCode), Win32Native.MakeHRFromErrorCode(errorCode), maybeFullPath);
182
183             case Win32Native.ERROR_SHARING_VIOLATION:
184                 if (str.Length == 0)
185                     throw new IOException(Environment.GetResourceString("IO.IO_SharingViolation_NoFileName"), Win32Native.MakeHRFromErrorCode(errorCode), maybeFullPath);
186                 else
187                     throw new IOException(Environment.GetResourceString("IO.IO_SharingViolation_File", str), Win32Native.MakeHRFromErrorCode(errorCode), maybeFullPath);
188
189             case Win32Native.ERROR_FILE_EXISTS:
190                 if (str.Length == 0)
191                     goto default;
192                 throw new IOException(Environment.GetResourceString("IO.IO_FileExists_Name", str), Win32Native.MakeHRFromErrorCode(errorCode), maybeFullPath);
193
194             case Win32Native.ERROR_OPERATION_ABORTED:
195                 throw new OperationCanceledException();
196
197             default:
198                 throw new IOException(Win32Native.GetMessage(errorCode), Win32Native.MakeHRFromErrorCode(errorCode), maybeFullPath);
199             }
200         }
201 #if !MONO
202         // An alternative to WinIOError with friendlier messages for drives
203         [System.Security.SecuritySafeCritical]  // auto-generated
204         internal static void WinIODriveError(String driveName) {
205             int errorCode = Marshal.GetLastWin32Error();
206             WinIODriveError(driveName, errorCode);
207         }
208
209         [System.Security.SecurityCritical]  // auto-generated
210         internal static void WinIODriveError(String driveName, int errorCode)
211         {
212             switch (errorCode) {
213             case Win32Native.ERROR_PATH_NOT_FOUND:
214             case Win32Native.ERROR_INVALID_DRIVE:
215                 throw new DriveNotFoundException(Environment.GetResourceString("IO.DriveNotFound_Drive", driveName));
216
217             default: 
218                 WinIOError(errorCode, driveName);                
219                 break;
220             }
221         }
222 #endif
223         internal static void WriteNotSupported() {
224             throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnwritableStream"));
225         }
226
227         internal static void WriterClosed() {
228             throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_WriterClosed"));
229         }
230 #if !MONO
231         // From WinError.h
232         internal const int ERROR_FILE_NOT_FOUND = Win32Native.ERROR_FILE_NOT_FOUND;
233         internal const int ERROR_PATH_NOT_FOUND = Win32Native.ERROR_PATH_NOT_FOUND;
234         internal const int ERROR_ACCESS_DENIED  = Win32Native.ERROR_ACCESS_DENIED;
235         internal const int ERROR_INVALID_PARAMETER = Win32Native.ERROR_INVALID_PARAMETER;
236 #endif
237     }
238 }