/
FileHelpers.cs
106 lines (96 loc) · 3.8 KB
/
FileHelpers.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#nullable enable
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using Microsoft.Windows.Sdk;
namespace Nerdbank.GitVersioning.ManagedGit
{
internal static class FileHelpers
{
private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
/// <summary>
/// Opens the file with a given path, if it exists.
/// </summary>
/// <param name="path">The path to the file.</param>
/// <param name="stream">The stream to open to, if the file exists.</param>
/// <returns><see langword="true" /> if the file exists; otherwise <see langword="false" />.</returns>
internal static bool TryOpen(string path, out FileStream? stream)
{
if (IsWindows)
{
var handle = PInvoke.CreateFile(path, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_FLAGS.FILE_SHARE_READ, lpSecurityAttributes: null, FILE_CREATE_FLAGS.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, null);
if (!handle.IsInvalid)
{
var fileHandle = new SafeFileHandle(handle.DangerousGetHandle(), ownsHandle: true);
handle.SetHandleAsInvalid();
stream = new FileStream(fileHandle, System.IO.FileAccess.Read);
return true;
}
else
{
stream = null;
return false;
}
}
else
{
if (!File.Exists(path))
{
stream = null;
return false;
}
stream = File.OpenRead(path);
return true;
}
}
/// <summary>
/// Opens the file with a given path, if it exists.
/// </summary>
/// <param name="path">The path to the file, as a null-terminated UTF-16 character array.</param>
/// <param name="stream">The stream to open to, if the file exists.</param>
/// <returns><see langword="true" /> if the file exists; otherwise <see langword="false" />.</returns>
internal static unsafe bool TryOpen(ReadOnlySpan<char> path, [NotNullWhen(true)] out FileStream? stream)
{
if (IsWindows)
{
HANDLE handle;
fixed (char* pPath = &path[0])
{
handle = PInvoke.CreateFile(pPath, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_FLAGS.FILE_SHARE_READ, null, FILE_CREATE_FLAGS.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, default);
}
if (!handle.Equals(Constants.INVALID_HANDLE_VALUE))
{
var fileHandle = new SafeFileHandle(handle, ownsHandle: true);
stream = new FileStream(fileHandle, System.IO.FileAccess.Read);
return true;
}
else
{
stream = null;
return false;
}
}
else
{
// Make sure to trim the trailing \0
string fullPath = GetUtf16String(path.Slice(0, path.Length - 1));
if (!File.Exists(fullPath))
{
stream = null;
return false;
}
stream = File.OpenRead(fullPath);
return true;
}
}
private static unsafe string GetUtf16String(ReadOnlySpan<char> chars)
{
fixed (char* pChars = chars)
{
return new string(pChars, 0, chars.Length);
}
}
}
}