Skip to content

SafeFileHandle FileStatus #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ internal static partial class Sys
{
[GeneratedDllImport(Libraries.SystemNative, EntryPoint = "SystemNative_ChMod", CharSet = CharSet.Ansi, SetLastError = true)]
internal static partial int ChMod(string path, int mode);

[GeneratedDllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FChMod", CharSet = CharSet.Ansi, SetLastError = true)]
internal static partial int FChMod(SafeHandle fd, int mode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ internal enum UserFlags : uint
[GeneratedDllImport(Libraries.SystemNative, EntryPoint = "SystemNative_LChflags", CharSet = CharSet.Ansi, SetLastError = true)]
internal static partial int LChflags(string path, uint flags);

[GeneratedDllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FChflags", CharSet = CharSet.Ansi, SetLastError = true)]
internal static partial int FChflags(SafeHandle fd, uint flags);

internal static readonly bool CanSetHiddenFlag = (LChflagsCanSetHiddenFlag() != 0);

[GeneratedDllImport(Libraries.SystemNative, EntryPoint = "SystemNative_LChflagsCanSetHiddenFlag")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,8 @@ internal struct TimeSpec
/// </returns>
[GeneratedDllImport(Libraries.SystemNative, EntryPoint = "SystemNative_UTimensat", CharSet = CharSet.Ansi, SetLastError = true)]
internal static unsafe partial int UTimensat(string path, TimeSpec* times);

[GeneratedDllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FUTimens", CharSet = CharSet.Ansi, SetLastError = true)]
internal static unsafe partial int FUTimens(SafeHandle fd, TimeSpec* times);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;

internal static partial class Interop
{
// Even though csc will by default use a sequential layout, a CS0649 warning as error
// is produced for un-assigned fields when no StructLayout is specified.
//
// Explicitly saying Sequential disables that warning/error for consumers which only
// use Stat in debug builds.
internal static partial class Kernel32
{
[StructLayout(LayoutKind.Sequential, Pack=4)]
internal struct BY_HANDLE_FILE_INFORMATION
{
internal uint dwFileAttributes;
internal FILE_TIME ftCreationTime;
internal FILE_TIME ftLastAccessTime;
internal FILE_TIME ftLastWriteTime;
internal uint dwVolumeSerialNumber;
internal uint nFileSizeHigh;
internal uint nFileSizeLow;
internal uint nNumberOfLinks;
internal uint nFileIndexHigh;
internal uint nFileIndexLow;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Kernel32
{
[DllImport(Libraries.Kernel32, SetLastError = true, ExactSpelling = true)]
internal static extern unsafe bool GetFileInformationByHandle(SafeFileHandle hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ internal void PopulateFrom(ref WIN32_FIND_DATA findData)
nFileSizeHigh = findData.nFileSizeHigh;
nFileSizeLow = findData.nFileSizeLow;
}

internal void PopulateFrom(ref BY_HANDLE_FILE_INFORMATION fileInformationData)
{
dwFileAttributes = (int) fileInformationData.dwFileAttributes;
ftCreationTime = fileInformationData.ftCreationTime;
ftLastAccessTime = fileInformationData.ftLastAccessTime;
ftLastWriteTime = fileInformationData.ftLastWriteTime;
nFileSizeHigh = fileInformationData.nFileSizeHigh;
nFileSizeLow = fileInformationData.nFileSizeLow;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,20 @@ internal static int FillAttributeInfo(string? path, ref Interop.Kernel32.WIN32_F
return errorCode;
}

internal static int FillAttributeInfo(SafeFileHandle fileHandle, ref Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data)
{

if (!Interop.Kernel32.GetFileInformationByHandle(
fileHandle,
out Interop.Kernel32.BY_HANDLE_FILE_INFORMATION fileInformationData))
{
return Marshal.GetLastWin32Error();
}

data.PopulateFrom(ref fileInformationData);
return Interop.Errors.ERROR_SUCCESS;
}

internal static bool IsPathUnreachableError(int errorCode)
{
switch (errorCode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
Link="Common\Interop\Windows\Interop.GET_FILEEX_INFO_LEVELS.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetFileAttributesEx.cs"
Link="Common\Interop\Windows\Interop.GetFileAttributesEx.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetFileInformationByHandle.cs"
Link="Common\Interop\Windows\Interop.GetFileInformationByHandle.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetFullPathNameW.cs"
Link="Common\Interop\Windows\Interop.GetFullPathNameW.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetLongPathNameW.cs"
Expand All @@ -58,6 +60,8 @@
Link="Common\Interop\Windows\Interop.SetThreadErrorMode.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.WIN32_FILE_ATTRIBUTE_DATA.cs"
Link="Common\Interop\Windows\Interop.WIN32_FILE_ATTRIBUTE_DATA.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.BY_HANDLE_FILE_INFORMATION.cs"
Link="Common\Interop\Windows\Interop.BY_HANDLE_FILE_INFORMATION.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.WIN32_FIND_DATA.cs"
Link="Common\Interop\Windows\Interop.WIN32_FIND_DATA.cs" />
<Compile Include="$(CoreLibSharedDir)System\IO\DisableMediaInsertionPrompt.cs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.CompilerServices;
using Microsoft.Win32.SafeHandles;

namespace System.IO.Tests
{
Expand Down
45 changes: 45 additions & 0 deletions src/libraries/System.IO.FileSystem/tests/File/GetSetAttributes.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Win32.SafeHandles;
using Xunit;

namespace System.IO.Tests
{
public class File_GetSetAttributes : BaseGetSetAttributes
{
protected override FileAttributes GetAttributes(string path) => File.GetAttributes(path);

protected FileAttributes GetAttributes(SafeFileHandle fileHandle) => File.GetAttributes(fileHandle);

protected override void SetAttributes(string path, FileAttributes attributes) => File.SetAttributes(path, attributes);

protected void SetAttributes(SafeFileHandle fileHandle, FileAttributes attributes) => File.SetAttributes(fileHandle, attributes);

// Getting only throws for File, not FileInfo
[Theory, MemberData(nameof(TrailingCharacters))]
public void GetAttributes_MissingFile(char trailingChar)
{
Assert.Throws<FileNotFoundException>(() => GetAttributes(GetTestFilePath() + trailingChar));
}


[Theory, MemberData(nameof(TrailingCharacters))]
[PlatformSpecific(TestPlatforms.Windows)]
public void GetAttributes_MissingFile_SafeFileHandle(char trailingChar)
{
Assert.Throws<FileNotFoundException>(() =>
{
using var fileHandle = File.OpenHandle(GetTestFilePath() + trailingChar);
GetAttributes(fileHandle);
});
}

// Getting only throws for File, not FileInfo
[Theory,
InlineData(":bar"),
Expand All @@ -30,10 +48,37 @@ public void GetAttributes_MissingAlternateDataStream_Windows(string streamName)
Assert.Throws<FileNotFoundException>(() => GetAttributes(streamName));
}

[Theory,
InlineData(":bar"),
InlineData(":bar:$DATA")]
[PlatformSpecific(TestPlatforms.Windows)]
public void GetAttributes_MissingAlternateDataStream_Windows_SafeFileHandle(string streamName)
{
string path = CreateItem();
streamName = path + streamName;

Assert.Throws<FileNotFoundException>(() =>
{
using var fileHandle = File.OpenHandle(streamName);
GetAttributes(fileHandle);
});
}

[Theory, MemberData(nameof(TrailingCharacters))]
public void GetAttributes_MissingDirectory(char trailingChar)
{
Assert.Throws<DirectoryNotFoundException>(() => GetAttributes(Path.Combine(GetTestFilePath(), "dir" + trailingChar)));
}

[Theory, MemberData(nameof(TrailingCharacters))]
[PlatformSpecific(TestPlatforms.Windows)]
public void GetAttributes_MissingDirectory_SafeFileHandle(char trailingChar)
{
Assert.Throws<DirectoryNotFoundException>(() =>
{
using var fileHandle = File.OpenHandle(Path.Combine(GetTestFilePath(), "dir" + trailingChar), access: FileAccess.ReadWrite);
GetAttributes(fileHandle);
});
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Win32.SafeHandles;

namespace System.IO.Tests
{
// Concrete class to run common file attributes tests on the File class
public class File_GetSetAttributesCommon : FileGetSetAttributes
{
protected override FileAttributes GetAttributes(string path) => File.GetAttributes(path);
protected FileAttributes GetAttributes(SafeFileHandle fileHandle) => File.GetAttributes(fileHandle);
protected override void SetAttributes(string path, FileAttributes attributes) => File.SetAttributes(path, attributes);
protected void SetAttributes(SafeFileHandle fileHandle, FileAttributes attributes) => File.SetAttributes(fileHandle, attributes);
}
}
Loading