Created
May 11, 2023 04:28
-
-
Save BinToss/d86eead5352f68e9f651a58449713775 to your computer and use it in GitHub Desktop.
What happens if a null, invalid, or closed handle if passed to GetFileType?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!meta | |
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}} | |
#!csharp | |
/** Q: What happens if a null, invalid, or closed handle is passed to GetFileType? | |
A: If the handle passed to GetFileType is null, invalid (i.e. 0 or -1), or closed, the Win32Error code will be ERROR_INVALID_HANDLE (6) | |
*/ | |
using Microsoft.Win32.SafeHandles; | |
using System.ComponentModel; | |
using System.IO; | |
using System.Runtime.InteropServices; | |
using System.Runtime.Versioning; | |
// 1. null/invalid | |
try | |
{ | |
using SafeFileHandle hFile = new(0, true); | |
FILE_TYPE type = GetFileType(hFile); | |
Console.WriteLine(type); // unreachable | |
} | |
catch(Exception ex) | |
{ | |
Console.WriteLine(ex); | |
/** System.ComponentModel.Win32Exception (6): The handle is invalid. | |
at Submission#2.GetFileType(SafeHandle hFile) | |
at Submission#2.<<Initialize>>d__0.MoveNext() | |
*/ | |
} | |
// 2. closed | |
try | |
{ | |
using FileStream fileStream = File.Open(@"C:\new.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite); | |
using SafeFileHandle hFile = new(fileStream.SafeFileHandle.DangerousGetHandle(), true); | |
fileStream.Close(); | |
FILE_TYPE type = GetFileType(hFile); | |
Console.WriteLine(type); // unreachable | |
} | |
catch(Exception ex) | |
{ | |
Console.WriteLine(ex); | |
/** System.ComponentModel.Win32Exception (6): The handle is invalid. | |
at Submission#2.GetFileType(SafeHandle hFile) | |
at Submission#2.<<Initialize>>d__0.MoveNext() | |
*/ | |
} | |
#region backend | |
// ! NOTE: modified to throw exception when native funtion writes non-success error code to thread | |
/// <exception cref="Win32Exception">GetFileType encountered an error.</exception> | |
/// <inheritdoc cref="GetFileType(HANDLE)"/> | |
[SupportedOSPlatform("windows5.1.2600")] | |
public static unsafe FILE_TYPE GetFileType(SafeHandle hFile) | |
{ | |
bool hFileAddRef = false; | |
try | |
{ | |
if (hFile is not object) | |
throw new ArgumentNullException(nameof(hFile)); | |
HANDLE hFileLocal; | |
hFile.DangerousAddRef(ref hFileAddRef); | |
hFileLocal = (HANDLE)hFile.DangerousGetHandle(); | |
FILE_TYPE type = GetFileType(hFileLocal); | |
Win32Exception ex = new(); | |
return ex.NativeErrorCode is 0 ? GetFileType(hFileLocal) : throw ex; | |
} | |
finally | |
{ | |
if (hFileAddRef) | |
hFile.DangerousRelease(); | |
} | |
} | |
/// <summary>Retrieves the file type of the specified file.</summary> | |
/// <param name="hFile">A handle to the file.</param> | |
/// <returns> | |
/// <para>The function returns one of the following values. </para> | |
/// <para>This doc was truncated.</para> | |
/// </returns> | |
/// <remarks> | |
/// <para><see href="https://docs.microsoft.com/windows/win32/api//fileapi/nf-fileapi-getfiletype">Learn more about this API from docs.microsoft.com</see>.</para> | |
/// </remarks> | |
[DllImport("KERNEL32.dll", ExactSpelling = true, SetLastError = true)] | |
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)] | |
[SupportedOSPlatform("windows5.1.2600")] | |
public static extern FILE_TYPE GetFileType(HANDLE hFile); | |
public readonly partial struct HANDLE : IEquatable<HANDLE> | |
{ | |
public readonly IntPtr Value; | |
public HANDLE(IntPtr value) => this.Value = value; | |
public static HANDLE Null => default; | |
public bool IsNull => Value == default; | |
public static implicit operator IntPtr(HANDLE value) => value.Value; | |
public static explicit operator HANDLE(IntPtr value) => new HANDLE(value); | |
public static bool operator ==(HANDLE left, HANDLE right) => left.Value == right.Value; | |
public static bool operator !=(HANDLE left, HANDLE right) => !(left == right); | |
public bool Equals(HANDLE other) => this.Value == other.Value; | |
public override bool Equals(object obj) => obj is HANDLE other && this.Equals(other); | |
public override int GetHashCode() => this.Value.GetHashCode(); | |
} | |
public enum FILE_TYPE : uint | |
{ | |
FILE_TYPE_UNKNOWN = 0U, | |
FILE_TYPE_DISK = 1U, | |
FILE_TYPE_CHAR = 2U, | |
FILE_TYPE_PIPE = 3U, | |
FILE_TYPE_REMOTE = 32768U, | |
} | |
#endregion backend |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment