mirror of https://github.com/dotnet/runtime
Merge a23d09c6dd
into 02596ba8d9
This commit is contained in:
commit
5f03ba8891
|
@ -7,6 +7,8 @@ internal static partial class Interop
|
|||
{
|
||||
internal static partial class FileAttributes
|
||||
{
|
||||
internal const int INVALID_FILE_ATTRIBUTES = -1;
|
||||
|
||||
internal const int FILE_ATTRIBUTE_NORMAL = 0x00000080;
|
||||
internal const int FILE_ATTRIBUTE_READONLY = 0x00000001;
|
||||
internal const int FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
@ -25,7 +26,7 @@ namespace System.IO
|
|||
|
||||
return
|
||||
(lastError == 0) &&
|
||||
(data.dwFileAttributes != -1) &&
|
||||
(data.dwFileAttributes != Interop.Kernel32.FileAttributes.INVALID_FILE_ATTRIBUTES) &&
|
||||
((data.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) != 0);
|
||||
}
|
||||
|
||||
|
@ -36,7 +37,7 @@ namespace System.IO
|
|||
|
||||
return
|
||||
(errorCode == 0) &&
|
||||
(data.dwFileAttributes != -1) &&
|
||||
(data.dwFileAttributes != Interop.Kernel32.FileAttributes.INVALID_FILE_ATTRIBUTES) &&
|
||||
((data.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == 0);
|
||||
}
|
||||
|
||||
|
@ -56,7 +57,14 @@ namespace System.IO
|
|||
|
||||
using (DisableMediaInsertionPrompt.Create())
|
||||
{
|
||||
if (!Interop.Kernel32.GetFileAttributesEx(path, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data))
|
||||
// Using 'GetFileAttributesEx' to get file attributes of a pipe
|
||||
// will inevitably open that pipe making it useless for a consumer,
|
||||
// thus we need to handle this case separately
|
||||
if (IsPipePath(path))
|
||||
{
|
||||
errorCode = GetFileAttributeInfoUsingFindFileApi(path, ref data);
|
||||
}
|
||||
else if (!Interop.Kernel32.GetFileAttributesEx(path, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data))
|
||||
{
|
||||
errorCode = Marshal.GetLastPInvokeError();
|
||||
|
||||
|
@ -79,19 +87,7 @@ namespace System.IO
|
|||
// pagefile.sys case. As such we're probably stuck filtering out specific
|
||||
// cases that we know we don't want to retry on.
|
||||
|
||||
Interop.Kernel32.WIN32_FIND_DATA findData = default;
|
||||
using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(path!, ref findData))
|
||||
{
|
||||
if (handle.IsInvalid)
|
||||
{
|
||||
errorCode = Marshal.GetLastPInvokeError();
|
||||
}
|
||||
else
|
||||
{
|
||||
errorCode = Interop.Errors.ERROR_SUCCESS;
|
||||
data.PopulateFrom(ref findData);
|
||||
}
|
||||
}
|
||||
errorCode = GetFileAttributeInfoUsingFindFileApi(path!, ref data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -104,12 +100,65 @@ namespace System.IO
|
|||
case Interop.Errors.ERROR_PATH_NOT_FOUND:
|
||||
case Interop.Errors.ERROR_NOT_READY: // Removable media not ready
|
||||
// Return default value for backward compatibility
|
||||
data.dwFileAttributes = -1;
|
||||
data.dwFileAttributes = Interop.Kernel32.FileAttributes.INVALID_FILE_ATTRIBUTES;
|
||||
return Interop.Errors.ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
|
||||
static int GetFileAttributeInfoUsingFindFileApi(string path, ref Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data)
|
||||
{
|
||||
Interop.Kernel32.WIN32_FIND_DATA findData = default;
|
||||
using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(path, ref findData))
|
||||
{
|
||||
if (handle.IsInvalid)
|
||||
{
|
||||
return Marshal.GetLastPInvokeError();
|
||||
}
|
||||
else
|
||||
{
|
||||
data.PopulateFrom(ref findData);
|
||||
return Interop.Errors.ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tells whether a given path is a Windows pipe path.
|
||||
/// Examples of pipe paths are:
|
||||
/// <list type="bullet">
|
||||
/// <item>
|
||||
/// <c>\\.\pipe\pipeName</c> - local pipe path
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <c>\\serverName\pipe\pipeName</c> - remote pipe path
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
private static bool IsPipePath([NotNullWhen(true)] string? path)
|
||||
{
|
||||
if (path is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ReadOnlySpan<char> pathSpan = path.AsSpan();
|
||||
if (!pathSpan.StartsWith(@"\\"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pathSpan = pathSpan.Slice(2);
|
||||
Span<Range> segments = stackalloc Range[3];
|
||||
int written = pathSpan.Split(segments, '\\');
|
||||
|
||||
// 3 segments of a pipe path:
|
||||
// 1) '.' or 'serverName'
|
||||
// 2) Constant 'pipe' segment
|
||||
// 3) Pipe name
|
||||
return written == 3 && pathSpan[segments[1]].SequenceEqual("pipe");
|
||||
}
|
||||
|
||||
internal static bool IsPathUnreachableError(int errorCode) =>
|
||||
|
|
|
@ -75,7 +75,8 @@ namespace System.IO
|
|||
// but Exists is supposed to return true or false.
|
||||
return false;
|
||||
}
|
||||
return (_data.dwFileAttributes != -1) && ((this is DirectoryInfo) == ((_data.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY));
|
||||
return (_data.dwFileAttributes != Interop.Kernel32.FileAttributes.INVALID_FILE_ATTRIBUTES) &&
|
||||
((this is DirectoryInfo) == ((_data.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace System.IO
|
|||
{
|
||||
Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = default;
|
||||
int errorCode = FileSystem.FillAttributeInfo(fullPath, ref data, returnErrorOnNotFound: true);
|
||||
bool result = (errorCode == Interop.Errors.ERROR_SUCCESS) && (data.dwFileAttributes != -1);
|
||||
bool result = (errorCode == Interop.Errors.ERROR_SUCCESS) && (data.dwFileAttributes != Interop.Kernel32.FileAttributes.INVALID_FILE_ATTRIBUTES);
|
||||
isDirectory = result && (data.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
|
||||
return result;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.IO.Pipes;
|
||||
using System.Threading;
|
||||
using Xunit;
|
||||
|
||||
namespace System.IO.Tests
|
||||
|
@ -230,6 +232,44 @@ namespace System.IO.Tests
|
|||
Assert.False(Exists(component));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[PlatformSpecific(TestPlatforms.Windows)] // Windows-specific pipes behavior
|
||||
public void CheckPipeExistsViaFileApi()
|
||||
{
|
||||
var pipeName = GetNamedPipeServerStreamName();
|
||||
using var server = new NamedPipeServerStream(pipeName);
|
||||
Assert.True(Exists(@$"\\.\pipe\{pipeName}"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[PlatformSpecific(TestPlatforms.Windows)] // Windows-specific pipes behavior
|
||||
public void CheckPipeDoesNotExistViaFileApi()
|
||||
{
|
||||
var pipeName = GetNamedPipeServerStreamName();
|
||||
new NamedPipeServerStream(pipeName).Dispose();
|
||||
Assert.False(Exists(@$"\\.\pipe\{pipeName}"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[PlatformSpecific(TestPlatforms.Windows)] // Windows-specific pipes behavior
|
||||
public void CheckingPipeExistenceViaFileApiDoesNotInvalidateIt()
|
||||
{
|
||||
var pipeName = GetNamedPipeServerStreamName();
|
||||
|
||||
using var server = new NamedPipeServerStream(pipeName);
|
||||
var connectedEvent = new ManualResetEventSlim(initialState: false);
|
||||
var connectResult = server.BeginWaitForConnection(_ => { connectedEvent.Set(); }, state: null);
|
||||
|
||||
Assert.True(Exists(@$"\\.\pipe\{pipeName}"));
|
||||
|
||||
using var client = new NamedPipeClientStream(pipeName);
|
||||
client.Connect(timeout: 1000);
|
||||
|
||||
server.EndWaitForConnection(connectResult);
|
||||
|
||||
Assert.True(connectedEvent.Wait(millisecondsTimeout: 1000));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue