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
Unify CreateFile pinvoke in SMA #18751
Unify CreateFile pinvoke in SMA #18751
Conversation
8428bb9
to
b102d42
Compare
fdbca38
to
280cb23
Compare
f6032c3
to
06493e6
Compare
| @@ -50,6 +52,14 @@ protected override bool ReleaseHandle() | |||
| // We use 'FindFirstFileW' instead of 'FindFirstFileExW' because the latter doesn't work correctly with Unicode file names on FAT32. | |||
| // See https://github.com/PowerShell/PowerShell/issues/16804 | |||
| [LibraryImport("api-ms-win-core-file-l1-1-0.dll", EntryPoint = "FindFirstFileW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can now remove EntryPoint parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather use explicit names everywhere as I have caught a problem with them several times already :-) Moreover LibraryImport source generator always adds this explicitly.
|
|
||
| // WARNING: This method does not implicitly handle long paths. Use CreateFile. | ||
| [LibraryImport("api-ms-win-core-file-l1-1-0.dll", EntryPoint = "CreateFileW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)] | ||
| private static unsafe partial SafeFileHandle CreateFilePrivate( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename method to the entry point name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the intent of the name is that code doesn't call the C function directly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SteveL-MSFT The private accessibility modifier should be sufficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could have the one extern signature that returns nint and just have the outer methods wrap that in the specific safe handle types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code was copied from .Net as well tested. Different teams create pinvoke code in .Net so it can have different styles. We have several PRs at the same time so it's also hard for us to follow one style. It is better to make a style correction later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fine to me, but there's a good amount of changes that should get another opinion
|
|
||
| // dwFlagsAndAttributes | ||
| [Flags] | ||
| internal enum FileAttributes : uint |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is missing a few things from https://learn.microsoft.com/en-us/dotnet/api/system.io.fileattributes?view=net-7.0. Personally I recommend having FileAttributes as one parameter and another custom enum just for the flags and in the CreateFile call bitor them together like https://gist.github.com/jborean93/246daf83f3aaca631dbca5652c3cc91e#file-get-smbapplicationkey-ps1-L165-L184.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a copy from old code. Really we have no need all the values and I kept them "just in case". Later we could correct style to follow .Net doc names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are trying to unify this, isn't it ideal to do it properly first then migrate the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I recommend having FileAttributes as one parameter and another custom enum just for the flags and in the CreateFile call bitor them together
Since this is low-level internal code for P/Invoke, there's no particular reason to complicate matters by using the public FileAttributes Enum.
My preference is to stay as close a possible to the underlying API, see: https://github.com/dotnet/pinvoke/blob/main/src/Kernel32/Kernel32+CreateFileFlags.cs
| System = 0x00000004, | ||
| Archive = 0x00000020, | ||
| Encrypted = 0x00004000, | ||
| Write_Through = 0x80000000, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you do keep this method, any reason why Write_Through is written like this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are not going to use original naming convention, i.e. FILE_FLAG_WRITE_THROUGH, use C# convention.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a copy from old code. Really we have no need all the values and I kept them "just in case". Later we could correct style to follow .Net doc names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really, there is no need to follow the names from the public .NET API.
src/System.Management.Automation/engine/remoting/common/RemoteSessionNamedPipe.cs
Show resolved
Hide resolved
| return CreateFilePrivate(lpFileName, (uint)dwDesiredAccess, dwShareMode, nint.Zero, dwCreationDisposition, dwFlagsAndAttributes, nint.Zero); | ||
| } | ||
|
|
||
| internal static unsafe nint CreateFileWithSafePipeHandle( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this return nint and not SafePipeHandle? I assume the purpose of having a separate call is to wrap it in a specific handle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I preferred to make minimal changes to this code so as not to break anything.
As you can see it needs a thorough revision so it could probably be replaced by .Net code and most importantly it compiles for Unix when it should not.
It takes more knowledge to get the job done. Perhaps you could take a look at this if you are interested. That would be great!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If that's the case I wouldn't have a CreateFileWithSafePipeHandle just a generic CreateFileW that returns the nint. In the future when we are ready to expose something that will return a SafePipeHandle then we can look at adding this new pipe specific call.
|
Since we do several PRs in parallel and copy code from both PowerShell and .Net, we already have a number of differences in style. This can be unified later if needed. I suppose it doesn't make sense to waste time adding unused constants or adding new enums because it's unlikely that this code will be used elsewhere. We aim to eliminate pinvokes in favor of .Net APIs. |
In this case dotnet do not seem like they are going to expose this in their own public API as per your recent issue dotnet/runtime#79335. My concern is we are moving code that can be improved in several ways and by not updating it to a better standard we run the risk of it staying like that forever. I don't want to stand in the way of this PR but my concern is we will move this across as is then in the future people might be reluctant to change it because that's how the code is. Granted that's not a big concern but why not just do things properly once rather than twice. |
For this reason we will not be able to remove all pinvokes, but so where possible it should be done. And we need to keep working with the .Net team on new APIs.
Migrating to LibraryImport helps us at least make the main code more readable and remove auxiliary code from it. I'm very happy that this happens. For example, the FileSystemProvider file will become almost 10% smaller! |
@SteveL-MSFT Do you ask about additional review? Who do you want to involve? |
|
if @jborean93 approves, I think that would be sufficient |
|
The only thing I think I really would like to see is the removal of the pipe specific extern signatures. Currently it is adding no benefit over a straight call to
The current code that calls The other stuff I've mentioned in the review is mostly cosmetic and I think are fine to evolve over time in separate PRs. |
I removed pipe path normalization since max pipe length is 256 https://learn.microsoft.com/en-us/windows/win32/ipc/pipe-names
|
|
At least for the pipes it should be possible to just use NamedPipeClientStream. I'm not aware of any limitations it has over the |
|
This PR has Quantification details
Why proper sizing of changes matters
Optimal pull request sizes drive a better predictable PR flow as they strike a
What can I do to optimize my changes
How to interpret the change counts in git diff output
Was this comment helpful? |
|
Handy links: |
PR Summary
Contributes to #18553.
PR Context
PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:or[ WIP ]to the beginning of the title (theWIPbot will keep its status check atPendingwhile the prefix is present) and remove the prefix when the PR is ready.(which runs in a different PS Host).