Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

GH Issue #15652 SqlFileStream Implementation on Windows - #29879

Merged
JeremyKuhne merged 21 commits into
dotnet:masterfrom
keeratsingh:gh_15652_SqlFileStream
Jul 5, 2018
Merged

JeremyKuhne merged 21 commits into
dotnet:masterfrom
keeratsingh:gh_15652_SqlFileStream

Conversation

@keeratsingh

Copy link
Copy Markdown

This Pull Request ports the SqlFileStream #15652 capability only on Windows.
SqlClient throws SqlFileStream is not supported on this platform exception for Non-Windows Platforms.

Client Server Feasible Comments
Windows Windows Yes Implemented by this PR.
Windows Linux No SQL Server on Linux does not support FileStream.
Linux Windows No Currently there is no way to open a file over SMB and pass the Extended Attributes.
Linux Linux No SQL Server on Linux does not support FileStream.

{
// 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

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suppressing warnings as per Jan's suggestion #29169

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suppressing warnings as per Jan's suggestion #29169

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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(

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@keeratsingh
keeratsingh requested a review from geleems May 23, 2018 22:49
@keeratsingh keeratsingh changed the title GH Issue #15652 SqlFileStream Implementaion GH Issue #15652 SqlFileStream Implementation May 23, 2018
return path;
}

static private void DemandAccessPermission

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this CAS-related stuff can be deleted.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is CAS-related stuff no longer valid/required ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, it's all nops on core.

@@ -0,0 +1,69 @@
// Licensed to the .NET Foundation under one or more agreements.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to use Win32 interop for this? i.e. why can't this just use FileStream?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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))

@stephentoub stephentoub May 24, 2018 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, it's Windows-only because SQL Server hands back a UNC path to the file to be opened?
cc: @JeremyKuhne

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

@JeremyKuhne JeremyKuhne May 24, 2018 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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));

@JeremyKuhne JeremyKuhne May 24, 2018 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uint

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, please match the casing of the docs. (Length, etc.)


public enum Access
{
/// <summary>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this link?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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}";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 JeremyKuhne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interop code is much better! Left some additional comments, some of which need to be addressed.

@keeratsingh

Copy link
Copy Markdown
Author

@dotnet-bot Test NETFX x86 Release Build

out IntPtr handle,
desiredAccess,
ref attributes,
FileHandle: out IntPtr handle,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tags like this (e.g. <a> have no meaning in a regular comment. The URL will still get highlighted, however.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed tag <a>

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the Versioning using?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must have been carried over, removing the using System.Runtime.Versioning;

#endregion

}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: empty lines


return tempTable;
}
private static void ExecuteNonQueryCommand(string cmdText, SqlConnection conn)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: no separating line

// 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()))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be necessary. Can you undo this, please?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undid the changes.

ObjectAttributes objectAttributes = ObjectAttributes.OBJ_CASE_INSENSITIVE,
void* eaBuffer = null,
uint eaLength = 0
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: please keep the trailing paren on the line above.

ushort deviceType,
ushort function,
byte method,
byte access )

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: extra space

};

public SqlFileStream
(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to normal styling as requested.

public sealed partial class SqlFileStream : System.IO.Stream
{
public SqlFileStream
(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to normal styling as requested.

@JeremyKuhne JeremyKuhne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good- there is some more style polish that I'l like to see. Otherwise looks great.

@keeratsingh

Copy link
Copy Markdown
Author

@dotnet-bot Test Windows x64 Debug Build

@keeratsingh

Copy link
Copy Markdown
Author

@dotnet-bot Test Linux x64 Release Build

@JeremyKuhne

Copy link
Copy Markdown
Member

Thanks for the follow-up @keeratsingh!

@JeremyKuhne
JeremyKuhne merged commit 2f7844a into dotnet:master Jul 5, 2018
@keeratsingh keeratsingh changed the title GH Issue #15652 SqlFileStream Implementation GH Issue #15652 SqlFileStream Implementation on Windows Jul 6, 2018
@keeratsingh keeratsingh added this to the 3.0 milestone Jul 6, 2018
@keithnicholson

Copy link
Copy Markdown

Wonderful! Thank you! Looking forward to the future release.

@keeratsingh
keeratsingh deleted the gh_15652_SqlFileStream branch July 11, 2018 22:45
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
…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
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants