Repository navigation
GH Issue #15652 SqlFileStream Implementation on Windows - #29879
Conversation
| { | ||
| // https://msdn.microsoft.com/en-us/library/bb432380.aspx | ||
| // https://msdn.microsoft.com/en-us/library/windows/hardware/ff566424.aspx | ||
| #pragma warning disable BCL0015 // Invalid Pinvoke call |
There was a problem hiding this comment.
Suppressing warnings as per Jan's suggestion #29169
There was a problem hiding this comment.
Please remove the pragma- shouldn't need it if we aren't including this on UAP.
In reply to: 190421828 [](ancestors = 190421828)
| internal partial class NtDll | ||
| { | ||
| // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680600(v=vs.85).aspx | ||
| #pragma warning disable BCL0015 // Invalid Pinvoke call |
There was a problem hiding this comment.
Suppressing warnings as per Jan's suggestion #29169
There was a problem hiding this comment.
You should not need this if you're only including the files in the non UAP builds. For example:
There was a problem hiding this comment.
@JeremyKuhne
Adding the condition '$(UWPCompatible)' != 'true' as per the suggestion throws an error TypesMustExist : Type 'System.Data.SqlTypes.SqlFileStream' does not exist in the implementation but it does exist in the contract.
| { | ||
| return ( CreateFile(eaBuffer: new Microsoft.Win32.SafeHandles.SafeFileHandle(IntPtr.Zero, true), eaLength: 0, path, rootDirectory,createDisposition, desiredAccess, shareAccess, fileAttributes, createOptions, objectAttributes) ); | ||
| } | ||
| internal unsafe static (int status, IntPtr handle) CreateFile( |
There was a problem hiding this comment.
Had to create a separate CreateFile Method as SqlFileStream requires the Extended Attributes buffer to be supplied and currently there is currently no way to do so other than NTCreateFile #29379
| return path; | ||
| } | ||
|
|
||
| static private void DemandAccessPermission |
There was a problem hiding this comment.
All of this CAS-related stuff can be deleted.
There was a problem hiding this comment.
Is CAS-related stuff no longer valid/required ?
There was a problem hiding this comment.
Right, it's all nops on core.
| @@ -0,0 +1,69 @@ | |||
| // Licensed to the .NET Foundation under one or more agreements. | |||
There was a problem hiding this comment.
This file looks identical to the .Uap.cs one. You could have a single SqlFileStream.Unsupported.cs file that's included in both the UAP and Unix builds.
That said, why can't it be supported? There's no way to make the majority of the functionality work on Unix or in UAP?
There was a problem hiding this comment.
I will create a singe file SqlFileStream.Unsupported.cs
As to why can't it be supported answered in the comments below.
| try | ||
| { | ||
|
|
||
| (int status, IntPtr handle) = Interop.NtDll.CreateFile( |
There was a problem hiding this comment.
Why do we need to use Win32 interop for this? i.e. why can't this just use FileStream?
There was a problem hiding this comment.
As per reasons mentioned in #29379, since it is not a real UNC path, the bogus path only has meaning in the context of this transaction, hence we cannot use FileStream directly.
| bool bRevertAssert = false; | ||
| try | ||
| { | ||
| SecurityPermission sp = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode); |
There was a problem hiding this comment.
All of the CAS-related code can be deleted.
| byte[] transactionContext = reader.GetSqlBytes(1).Buffer; | ||
|
|
||
| // Create the SqlFileStream | ||
| using (Stream fileStream = new SqlFileStream(path, transactionContext, FileAccess.Read, FileOptions.SequentialScan, allocationSize: 0)) |
There was a problem hiding this comment.
I see, it's Windows-only because SQL Server hands back a UNC path to the file to be opened?
cc: @JeremyKuhne
There was a problem hiding this comment.
Explained in the comment above and more information in comments #15652
Also, this is Windows-only because SQL Server on Linux doesn't support FileStream currently.
In case of Linux Client and Windows SQL Server, as per discussions with Robert Dorr, currently there is no way to open a file over SMB and pass the Extended Attributes on Linux.
| /// <summary> | ||
| /// The offset of the next FILE_FULL_EA_INFORMATION-type entry. This member is zero if no other entries follow this one. | ||
| /// </summary> | ||
| internal UInt32 nextEntryOffset; |
There was a problem hiding this comment.
nit: we use the C# keywords for types (uint, byte, byte, ushort, byte) #Resolved
| public unsafe OBJECT_ATTRIBUTES(UNICODE_STRING* objectName, ObjectAttributes attributes, IntPtr rootDirectory) | ||
| { | ||
| Length = (uint)sizeof(OBJECT_ATTRIBUTES); | ||
| Length = (uint)Marshal.SizeOf(typeof(OBJECT_ATTRIBUTES)); |
There was a problem hiding this comment.
Don't change this to Marshal.SizeOf- it is much more expensive. #Resolved
| /// <summary> | ||
| /// Specifies the size, in bytes, of this structure. | ||
| /// </summary> | ||
| internal UInt32 length; |
There was a problem hiding this comment.
Also, please match the casing of the docs. (Length, etc.)
|
|
||
| public enum Access | ||
| { | ||
| /// <summary> |
There was a problem hiding this comment.
You've got tabs in here, please use spaces for indenting
| internal partial class Kernel32 | ||
| { | ||
| /// <summary> | ||
| /// <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/buffer-descriptions-for-i-o-control-codes">RequiredAccess</a>. |
There was a problem hiding this comment.
There was a problem hiding this comment.
Thank you for catching this, must have mixed up the links. I have updated the link with the second link, since the first link throws error '404 Content not found'
| /// Indicates the type of access that a caller must request when opening the file object that represents the device (see IRP_MJ_CREATE). | ||
| /// </summary> | ||
|
|
||
| public enum Access |
There was a problem hiding this comment.
You can make this a [Flags] to represent that you can OR the values. The other option (given that Any is 0), is to define FILE_READWRITE_ACCESS with a comment noting that it isn't actually defined in Windows, but we're including it for convenience.
There was a problem hiding this comment.
I have added the [Flags] attribute to the enum.
| /// <summary> | ||
| /// The I/O manager sends the IRP for any caller that has a handle to the file object that represents the target device object. | ||
| /// </summary> | ||
| FILE_ANY_ACCESS, |
There was a problem hiding this comment.
Should call out that this value should be avoided. (https://docs.microsoft.com/en-us/previous-versions/windows/hardware/design/dn614603) Also, consider actually putting in the defined values explicitly (i.e. 0x00, 0x01, etc.)
There was a problem hiding this comment.
The link above throws error 404 Content not found, could you kindly confirm if the link is correct.
| /// <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/buffer-descriptions-for-i-o-control-codes">TransferType</a>. | ||
| /// Indicates how the system will pass data between the caller of DeviceIoControl (or IoBuildDeviceIoControlRequest) and the driver that handles the IRP. | ||
| /// </summary> | ||
| public enum Method |
There was a problem hiding this comment.
It would be better to name this TransferType to match what it is used for. Or perhaps IoControlTransferType.
| } | ||
|
|
||
| internal unsafe static (int status, IntPtr handle) CreateFile( | ||
| void* eaBuffer, |
There was a problem hiding this comment.
Put new overload parameters at the end (eaBuffer & eaLength);
| string formatPath = string.Empty; | ||
| string uniqueId = string.Empty; | ||
|
|
||
| formatPath = System.IO.PathInternal.IsDeviceUNC(path.AsSpan()) ? @"\??" : @"\??\UNC\{0}\{1}"; |
There was a problem hiding this comment.
nit: there is an implicit conversion to span from string, you shouldn't need .AsSpan(). Additionally you're not building it right if it is a device path already. If it is \\.\UNC\Server\Share\SomePath you need to change \\. to \??, not trim off \\. You also still need to add your uniqueId.
JeremyKuhne
left a comment
There was a problem hiding this comment.
Interop code is much better! Left some additional comments, some of which need to be addressed.
|
@dotnet-bot Test NETFX x86 Release Build |
| out IntPtr handle, | ||
| desiredAccess, | ||
| ref attributes, | ||
| FileHandle: out IntPtr handle, |
There was a problem hiding this comment.
nit: These aren't necessary, in fact you're missing one for statusBlock. The only reason I added them later was to be explicit about what null was (AllocationSize:). In earlier versions of C# you had to name all of the arguments after named one. This really should only have just that one explicit- it helps when reading the code when explicitly calling out what arguments are when passing things like null, true, false, and other unnamed constant values. (So you don't have to look at the called method to understand what the value is.)
There was a problem hiding this comment.
Changed code to only one explicit AllocationSize as the other arguments are self descriptive.
| byte access ) | ||
| { | ||
|
|
||
| // <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/develop/how-to-select-and-configure-the-device-fundamental-tests">MaxFunctionCode</a> method. |
There was a problem hiding this comment.
Tags like this (e.g. <a> have no meaning in a regular comment. The URL will still get highlighted, however.
| using Microsoft.Win32.SafeHandles; | ||
| using System; | ||
| using System.Runtime.InteropServices; | ||
| using System.Runtime.Versioning; |
There was a problem hiding this comment.
Must have been carried over, removing the using System.Runtime.Versioning;
| #endregion | ||
|
|
||
| } | ||
|
|
|
|
||
| return tempTable; | ||
| } | ||
| private static void ExecuteNonQueryCommand(string cmdText, SqlConnection conn) |
| // shimming method. (Or making a change that doesn't impact normalization, such as adding a filename to a | ||
| // normalized base path.) | ||
| if (IsPartiallyQualified(path) || IsDevice(path)) | ||
| if (IsPartiallyQualified(path.AsSpan()) || IsDevice(path.AsSpan())) |
There was a problem hiding this comment.
This shouldn't be necessary. Can you undo this, please?
| ObjectAttributes objectAttributes = ObjectAttributes.OBJ_CASE_INSENSITIVE, | ||
| void* eaBuffer = null, | ||
| uint eaLength = 0 | ||
| ) |
There was a problem hiding this comment.
nit: please keep the trailing paren on the line above.
| ushort deviceType, | ||
| ushort function, | ||
| byte method, | ||
| byte access ) |
| }; | ||
|
|
||
| public SqlFileStream | ||
| ( |
There was a problem hiding this comment.
I don't see this sort of indenting for parameter parenthesis in the other files in this assembly. I know the original source files were like this, but it would be worth following the CoreFX styles and keep the parens next to the arguments. There aren't many arguments here so they can go on one line. Also, unless there is a conflict, you can remove System.IO from the type names.
There was a problem hiding this comment.
Updated to normal styling as requested.
| public sealed partial class SqlFileStream : System.IO.Stream | ||
| { | ||
| public SqlFileStream | ||
| ( |
There was a problem hiding this comment.
Commented elsewhere. Can you please pull the arguments into our normal styling? Also it looks like you have more usings than needed in this file.
There was a problem hiding this comment.
Updated to normal styling as requested.
JeremyKuhne
left a comment
There was a problem hiding this comment.
Looks pretty good- there is some more style polish that I'l like to see. Otherwise looks great.
|
@dotnet-bot Test Windows x64 Debug Build |
|
@dotnet-bot Test Linux x64 Release Build |
|
Thanks for the follow-up @keeratsingh! |
|
Wonderful! Thank you! Looking forward to the future release. |
…efx#29879) * Initial port of SqlFileStream * Added SqlFileStreamTest * Cleanup code * Updated file paths after catchup merge. * Added newline at the end of Strings.resx * Fixed cosmetic changes * Replaced null SafeHandle call * Added headers to SqlFileStreamTest.cs * Addressed review feedback by Stephen and Jeremy * Fixed filename UnSupported.cs to Unsupported.cs to match case in Linux builds. * Addressed review comments * Made SqlFileStream netcoreapp and windows specific. * Update EaName to include Null Terminator * Fixed cosmetic issues * Addressed Dan's review feedback. Removed initially added file Interop.GetFullPathName.cs as is it no longer being used. * Addressed Jeremy's review comments. * Addressed Jeremy's review comments about style polish. Commit migrated from dotnet/corefx@2f7844a
This Pull Request ports the SqlFileStream #15652 capability only on Windows.
SqlClient throws
SqlFileStream is not supported on this platformexception for Non-Windows Platforms.