1 //------------------------------------------------------------------------------
2 // <copyright file="SafeNativeMethods.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 // <owner current="true" primary="false">Microsoft</owner>
8 //------------------------------------------------------------------------------
11 using System.Diagnostics;
13 using System.Runtime.InteropServices;
14 using System.Security;
15 using Microsoft.Win32.SafeHandles;
16 using System.Data.Common;
17 using System.Runtime.Versioning;
18 using System.Diagnostics.CodeAnalysis;
20 namespace System.Data.SqlTypes
22 [SuppressUnmanagedCodeSecurity]
23 internal static class UnsafeNativeMethods
25 #region PInvoke methods
27 [DllImport("NtDll.dll", CharSet = CharSet.Unicode)]
28 [ResourceExposure(ResourceScope.Machine)]
29 internal static extern UInt32 NtCreateFile
31 out Microsoft.Win32.SafeHandles.SafeFileHandle fileHandle,
33 ref OBJECT_ATTRIBUTES objectAttributes,
34 out IO_STATUS_BLOCK ioStatusBlock,
35 ref Int64 allocationSize,
36 UInt32 fileAttributes,
37 System.IO.FileShare shareAccess,
38 UInt32 createDisposition,
44 [DllImport("Kernel32.dll", SetLastError = true)]
45 [ResourceExposure(ResourceScope.None)]
46 internal static extern FileType GetFileType
48 Microsoft.Win32.SafeHandles.SafeFileHandle hFile
51 // do not use this PInvoke directly, use SafeGetFullPathName instead
52 [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
53 [ResourceExposure(ResourceScope.Machine)]
54 private static extern int GetFullPathName
59 IntPtr lpFilePartOrNull
63 /// safe wrapper for GetFullPathName
64 /// check that the path length is less than Int16.MaxValue before calling this API!
66 [ResourceExposure(ResourceScope.Machine)]
67 [ResourceConsumption(ResourceScope.Machine)]
68 internal static string SafeGetFullPathName(string path)
70 Debug.Assert(path != null, "path is null?");
71 // make sure to test for Int16.MaxValue limit before calling this method
72 // see the below comment re GetLastWin32Error for the reason
73 Debug.Assert(path.Length < Int16.MaxValue);
75 // since we expect network paths, the 'full path' is expected to be the same size
76 // as the provided one. we still need to allocate +1 for null termination
77 StringBuilder buffer = new StringBuilder(path.Length + 1);
79 int cchRequiredSize = GetFullPathName(path, buffer.Capacity, buffer, IntPtr.Zero);
81 // if our buffer was smaller than required, GetFullPathName will succeed and return us the required buffer size with null
82 if (cchRequiredSize > buffer.Capacity)
84 // we have to reallocate and retry
85 buffer.Capacity = cchRequiredSize;
86 cchRequiredSize = GetFullPathName(path, buffer.Capacity, buffer, IntPtr.Zero);
89 if (cchRequiredSize == 0)
91 // GetFullPathName call failed
92 int lastError = Marshal.GetLastWin32Error();
95 // we found that in some cases GetFullPathName fail but does not set the last error value
96 // for example, it happens when the path provided to it is longer than 32K: return value is 0 (failure)
97 // but GetLastError was zero too so we raised Win32Exception saying "The operation completed successfully".
98 // To raise proper "path too long" failure, check the length before calling this API.
99 // For other (yet unknown cases), we will throw InvalidPath message since we do not know what exactly happened
100 throw ADP.Argument(Res.GetString(Res.SqlFileStream_InvalidPath), "path");
104 System.ComponentModel.Win32Exception e = new System.ComponentModel.Win32Exception(lastError);
105 ADP.TraceExceptionAsReturnValue(e);
110 // this should not happen since we already reallocate
111 Debug.Assert(cchRequiredSize <= buffer.Capacity, string.Format(
112 System.Globalization.CultureInfo.InvariantCulture,
113 "second call to GetFullPathName returned greater size: {0} > {1}",
117 return buffer.ToString();
120 // RTM versions of Win7 and Windows Server 2008 R2
121 private static readonly Version ThreadErrorModeMinOsVersion = new Version(6, 1, 7600);
123 // do not use this method directly, use SetErrorModeWrapper instead
124 [DllImport("Kernel32.dll", ExactSpelling = true)]
125 [ResourceExposure(ResourceScope.Process)]
126 private static extern uint SetErrorMode(uint mode);
128 // do not use this method directly, use SetErrorModeWrapper instead
129 // this API exists since Windows 7 / Windows Server 2008 R2
130 [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true)]
131 [ResourceExposure(ResourceScope.None)]
132 [SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage")]
133 private static extern bool SetThreadErrorMode(uint newMode, out uint oldMode);
136 /// this method uses thread-safe version of SetErrorMode on Windows 7/Windows Server 2008 R2 operating systems.
138 [ResourceExposure(ResourceScope.Process)] // None on Windows7 / Windows Server 2008 R2 or later
139 [ResourceConsumption(ResourceScope.Process)]
140 internal static void SetErrorModeWrapper(uint mode, out uint oldMode)
142 if (Environment.OSVersion.Version >= ThreadErrorModeMinOsVersion)
144 // safe to use new API
145 if (!SetThreadErrorMode(mode, out oldMode))
147 throw new System.ComponentModel.Win32Exception();
152 // cannot use the new SetThreadErrorMode API on current OS, fallback to the old one
153 oldMode = SetErrorMode(mode);
157 [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
158 [ResourceExposure(ResourceScope.Machine)]
159 internal static extern bool DeviceIoControl
161 Microsoft.Win32.SafeHandles.SafeFileHandle fileHandle,
167 out uint cbBytesReturned,
171 [DllImport("NtDll.dll")]
172 [ResourceExposure(ResourceScope.None)]
173 internal static extern UInt32 RtlNtStatusToDosError
178 #region definitions from devioctl.h
180 internal const ushort FILE_DEVICE_FILE_SYSTEM = 0x0009;
197 internal static uint CTL_CODE
205 if ( function > 4095 )
206 throw ADP.ArgumentOutOfRange ( "function" );
208 return (uint) ( ( deviceType << 16 ) | ( access << 14 ) | ( function << 2 ) | method );
217 internal const int ERROR_INVALID_HANDLE = 6;
218 internal const int ERROR_MR_MID_NOT_FOUND = 317;
220 internal const uint STATUS_INVALID_PARAMETER = 0xc000000d;
221 internal const uint STATUS_SHARING_VIOLATION = 0xc0000043;
222 internal const uint STATUS_OBJECT_NAME_NOT_FOUND = 0xc0000034;
226 internal const uint SEM_FAILCRITICALERRORS = 0x0001;
228 internal enum FileType : uint
230 Unknown = 0x0000, // FILE_TYPE_UNKNOWN
231 Disk = 0x0001, // FILE_TYPE_DISK
232 Char = 0x0002, // FILE_TYPE_CHAR
233 Pipe = 0x0003, // FILE_TYPE_PIPE
234 Remote = 0x8000 // FILE_TYPE_REMOTE
237 #region definitions from wdm.h
239 [StructLayoutAttribute(LayoutKind.Sequential)]
240 internal struct OBJECT_ATTRIBUTES
243 internal IntPtr rootDirectory;
244 internal SafeHandle objectName;
245 internal int attributes;
246 internal IntPtr securityDescriptor;
247 internal SafeHandle securityQualityOfService;
250 [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
251 internal struct UNICODE_STRING
253 internal UInt16 length;
254 internal UInt16 maximumLength;
255 internal string buffer;
258 // VSTFDevDiv # 547461 [Backport SqlFileStream fix on Win7 to QFE branch]
259 // Win7 enforces correct values for the _SECURITY_QUALITY_OF_SERVICE.qos member.
260 // taken from _SECURITY_IMPERSONATION_LEVEL enum definition in winnt.h
261 internal enum SecurityImpersonationLevel
264 SecurityIdentification,
265 SecurityImpersonation,
269 [StructLayoutAttribute(LayoutKind.Sequential)]
270 internal struct SECURITY_QUALITY_OF_SERVICE
272 internal UInt32 length;
273 [MarshalAs(UnmanagedType.I4)]
274 internal int impersonationLevel;
275 internal byte contextDynamicTrackingMode;
276 internal byte effectiveOnly;
279 [StructLayoutAttribute(LayoutKind.Sequential)]
280 internal struct IO_STATUS_BLOCK
282 internal UInt32 status;
283 internal IntPtr information;
286 [StructLayoutAttribute(LayoutKind.Sequential)]
287 internal struct FILE_FULL_EA_INFORMATION
289 internal UInt32 nextEntryOffset;
291 internal Byte EaNameLength;
292 internal UInt16 EaValueLength;
293 internal Byte EaName;
297 internal enum CreateOption : uint
299 FILE_WRITE_THROUGH = 0x00000002,
300 FILE_SEQUENTIAL_ONLY = 0x00000004,
301 FILE_NO_INTERMEDIATE_BUFFERING = 0x00000008,
302 FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020,
303 FILE_RANDOM_ACCESS = 0x00000800
306 internal enum CreationDisposition : uint
313 FILE_OVERWRITE_IF = 5
318 #region definitions from winnt.h
320 internal const int FILE_READ_DATA = 0x0001;
321 internal const int FILE_WRITE_DATA = 0x0002;
322 internal const int FILE_READ_ATTRIBUTES = 0x0080;
323 internal const int SYNCHRONIZE = 0x00100000;
327 #region definitions from ntdef.h
330 internal enum Attributes : uint
332 Inherit = 0x00000002,
333 Permanent = 0x00000010,
334 Exclusive = 0x00000020,
335 CaseInsensitive = 0x00000040,
337 OpenLink = 0x00000100,
338 KernelHandle = 0x00000200,
339 ForceAccessCheck = 0x00000400,
340 ValidAttributes = 0x000007F2