| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
|
jeffbi I updated the description as this seems the fix for #1930, but please correct it if I'm wrong. The last comment of #1930 shows:
Steve Lee (@SteveL-MSFT), do you mean that bug had already been fixed by Ilya (@iSazonov)? |
Sorry, something went wrong.
|
Dongbo Wang (@daxian-dbw) Yes, it is a fix for #1930. I had that at the end of the pull-request title, but it looks like it got clipped off. I've updated the description with more information. I believe Steve Lee (@SteveL-MSFT)'s comment referred to fixing the wording on an earlier comment. |
Sorry, something went wrong.
It was just a typo. |
Sorry, something went wrong.
|
I tested Test-Path /etc/sysctl.conf
Test-Path /etc/sysctl.CONFon WSL and Test-Path is case-sensitive. Do we really need additional code here? |
Sorry, something went wrong.
|
Dongbo Wang (@daxian-dbw) yeah, the 'fixed' statement referred to a typo in the comment Ilya (@iSazonov) caught, nit that the issue was fixed |
Sorry, something went wrong.
|
Ilya (@iSazonov) The goal of the original code was to ensure that the cmdlet did not attempt to copy a file onto itself, and it did so by doing a case-insensitive compare of the two normalized paths. That worked fine on FAT volumes, on NTFS volumes under Windows in its default mode, and on HFS+ volumes on OS X. In your example, it would consider /etc/sysctl.conf and /etc/sysctl.CONF to be the same file and would not allow the copy. On a case-sensitive file system such as ext under Linux, or NTFS under either Linux or OS X, those two paths are generally not the same file, so the copy should be allowed to continue, which is the complaint in issue #1930. I'm fairly confident that if you ran copy-item /etc/sysctl.conf /etc/sysctl.CONF under WSL it would fail with an error saying it cannot copy the file onto itself. Then consider links. If file A is a file on a volume, and file B is a hard or symbolic link to file A, copying A to B would actually be copying A onto itself, which the cmdlet does not allow but cannot be detected by merely comparing two path strings. The new code determines whether two paths refer to the same file (the goal of the original code) regardless of what the paths appear to be. It works on HFS+, ext, FAT, and NTFS file systems. For NTFS file systems, it does the right thing under Windows, where the volume is case-insensitive, and on Mac/Linux where the volume is case-sensitive. And it works for hard and symbolic links on those file systems that support them. |
Sorry, something went wrong.
|
My question was only whether we can use existing code without new low level code? Name : powershell
Length : 0
CreationTime : 3/21/2017 11:18:52 AM
LastWriteTime : 3/21/2017 11:18:52 AM
LastAccessTime : 3/21/2017 11:18:52 AM
Mode : -a---l
LinkType : SymbolicLink
Target : C:\Users\sie\Documents\GitHub\iSazonov\PowerShell\debug\powershell.exe
VersionInfo : File: C:\Users\sie\Documents\GitHub\iSazonov\PowerShell\debug\powershellHere Target contains true value for soft and hard links. We can use Mode or LinkType to detect links. So here we can make the code more simple. We should create a new API to compare path and place it in engen\Utils.cs or PathUtils.cs |
Sorry, something went wrong.
|
This works differently in Linux. PS> new-item junk.txt -value "stuff"
PS> get-item j* | select name,mode,attributes,length,linktype,target
Name : junk.txt
Mode : ------
Attributes : Normal
Length : 5
LinkType :
Target :
PS> new-item -itemtype symboliclink -path junk-sym.txt -value junk.txt
PS> new-item -itemtype hardlink -path junk-hard.txt -value junk.txt
PS> get-item j* | select name,mode,attributes,length,linktype,target
Name : junk-hard.txt
Mode : -----l
Attributes : Normal
Length : 5
LinkType : HardLink
Target :
Name : junk-sym.txt
Mode : -----l
Attributes : ReparsePoint
Length : 24
LinkType : SymbolicLink
Target : {/home/jeff/junk/junk.txt}
Name : junk.txt
Mode : -----l
Attributes : Normal
Length : 5
LinkType : HardLink
Target :
Here, the symbolic link points to its target, but the hard link does not. Also, once the hard link was created, the original file became a hard link as well. Linux (or the ext file system) does not distinguish between a hard link and the "original" file. A slightly off-topic question: Note that the symbolic link's attributes property says "ReparsePoint". That makes sense for Windows, but does it for Linux? |
Sorry, something went wrong.
|
jeffbi Sorry for mesh in my previous comment.
I believe we should fix this locally - behavior on all platforms must be the same. So my suggestion is don't block the PR, continue the code review and open new Issue (if you confirm that we have inconsistency in file provider with soft/hard links on different platforms). |
Sorry, something went wrong.
|
Is this being reviewed, or is it awaiting something from me? |
Sorry, something went wrong.
|
I originally thought that we already have full compliance with links on all platforms as associated problems has been closed both locally and in CoreFX. As you pointed out it is not. I propose to open a new issue and collect the inconsistencies there. Anyway we need to fix it now or later. I need your help with this on Unix. Dongbo Wang (@daxian-dbw) Could you please review my thoughts? |
Sorry, something went wrong.
|
Ilya (@iSazonov) I don't think we can "fix" Target, at least for Unix. Short of walking the file system, like the UNIX find command does, I don't believe there is a way to discover all the hard links to a given inode. An inode has a count of links that refer to it, but not a list of the actual links. My low-level code does not attempt to find all paths to an inode, just whether two paths point to the same inode. There is an open request issue in corefx (dotnet/corefx#10120) to implement this in corefx. In PowerShell 5.1 on my Windows 10 box, the Target property contains a collection of other hard links to the same file. On PowerShell for CoreCLR, Target is empty. The code for discovering the links on Windows is #if-ed out, with a comment saying the Windows API functions FindFirstFileName and FindNextFileName are not supported in CoreCLR. Is that no longer the case? I re-enabled that code, using the appropriate DLL name from here, and I'm able to populate Target on CoreCLR. That code, though, does have another instance of case-insensitive path comparison, which is what started this PR in the first place. I have come across a few other issues that are related to links, one in New-Item and two that directly affect #621 (the latter two are, I believe, corefx issues: see dotnet/corefx#17843 and dotnet/corefx#17844). Do we want to create a single issue as a catch-all for link-related items? |
Sorry, something went wrong.
|
jeffbi Great ** 2! 😄 Thanks!
Sorry for the delay of the PR. |
Sorry, something went wrong.
There was a problem hiding this comment.
Please add tests.
Sorry, something went wrong.
There was a problem hiding this comment.
Please renew the comments.
Sorry, something went wrong.
There was a problem hiding this comment.
Fixed
Sorry, something went wrong.
There was a problem hiding this comment.
path_two?
Sorry, something went wrong.
There was a problem hiding this comment.
Fixed
Sorry, something went wrong.
There was a problem hiding this comment.
Please correct the comment.
Sorry, something went wrong.
There was a problem hiding this comment.
Fixed
Sorry, something went wrong.
There was a problem hiding this comment.
I believe it works for both files and directories. Parameters is "path" too. So maybe rename to IsSamePath?
Sorry, something went wrong.
There was a problem hiding this comment.
I agree that this could use a better name, since it does work for both files and directories, but I'm not sure that IsSamePath is the best choice. I avoided IsSamePath because two different paths can arrive at the same destination. I went with IsSameFile just because the docs for the stat function and the GetFileInformationByHandle both just use the term "file" even though they both work for files and directories.
Sorry, something went wrong.
There was a problem hiding this comment.
Maybe good comments (on high level API too) and/or IsSameTarget or something like that?
Sorry, something went wrong.
There was a problem hiding this comment.
Renamed to IsSameFileSystemItem
Sorry, something went wrong.
There was a problem hiding this comment.
The same as for IsSameFile - maybe rename to WinIsSamePath
Sorry, something went wrong.
There was a problem hiding this comment.
Renamed to IsSameFileSystemItem
Sorry, something went wrong.
There was a problem hiding this comment.
Please remove the comment or make it full and clear.
Sorry, something went wrong.
There was a problem hiding this comment.
Fixed
Sorry, something went wrong.
There was a problem hiding this comment.
Can we use NativeMethods.CreateFile here?
Sorry, something went wrong.
There was a problem hiding this comment.
Not really, but that code could have been a lot better. I've updated it.
Sorry, something went wrong.
There was a problem hiding this comment.
Unneeded formatting. Please renew the comments.
Sorry, something went wrong.
There was a problem hiding this comment.
Fixed
Sorry, something went wrong.
There was a problem hiding this comment.
Unneeded formatting. Please renew the comments.
Sorry, something went wrong.
There was a problem hiding this comment.
Fixed
Sorry, something went wrong.
|
Dongbo Wang (@daxian-dbw) This has been waiting for approval/merge of PR #3509 because the Pester tests should be using New-Item to create directory symbolic links. I can get around that by shelling out to cmd.exe to run the mklink program, but that would mean revisiting the test script once the PR has been merged. Perhaps I could open a new issue to update the test. Would this be acceptable? |
Sorry, something went wrong.
|
jeffbi Thanks for letting me know. I noticed that Ilya (@iSazonov) has signed off #3509. I will quickly go through it and merge the PR if I don't spot anything obvious. |
Sorry, something went wrong.
|
Dongbo Wang (@daxian-dbw) I think there are discussions required for #3509 regarding the proper way to create symlinks in various circumstances under Windows, and that that's why approval/merging of that PR is taking a while. |
Sorry, something went wrong.
Sorry, something went wrong.
…accurate, cross-platform test (#1930) Changes per code review * Cleaned up comments in .cpp file * Renamed IsSameFile to IsSameFileSystemItem * Removed comment about PosixSemantics * Added PosixSemantics to CreateFile call * Provide additional information in exception when paths point to same destination. * Added tests
| $principal = New-Object System.Security.Principal.WindowsPrincipal($WinId) | ||
| $admin = [System.Security.Principal.WindowsBuiltInRole]::Administrator | ||
|
|
||
| return $principal.IsInRole($admin) |
There was a problem hiding this comment.
Usually we set -Tags @('CI', 'RequireAdminOnWindows').
Sorry, something went wrong.
| catch | ||
| { | ||
| # we expected the copy to fail and it did. make sure it failed the right way | ||
| $_.FullyQualifiedErrorId | Should Be "CopyError,Microsoft.PowerShell.Commands.CopyItemCommand" |
There was a problem hiding this comment.
Please use ShouldBeErrorId
$exc = {
... } | ShouldBeErrorId ...
$exc.Exception | Should BeOfType System.IO.IOException
...
Sorry, something went wrong.
| { | ||
| # we expected the copy to succeed. make sure it did | ||
| Test-Path $testCase.Destination | Should Be $true | ||
| Remove-Item -Path $testCase.Destination -Force -ErrorAction SilentlyContinue |
There was a problem hiding this comment.
If previous Should Be is failed the cleanup code will be unreacheable.
Please move the cleanup code to AfterEach.
Sorry, something went wrong.
| # Test the ability to avoid an item copying onto itself | ||
| function TestSelfCopy($testCase) | ||
| { | ||
| It "$($testCase.Name)" -Skip:($testCase.SkipIf) { |
There was a problem hiding this comment.
With moving to 'RequireAdminOnWindows' I believe we can use It "" -TestCase $testCases directly without TestSelfCopy
Sorry, something went wrong.
| $result | Should Be $level1_0 | ||
| } | ||
|
|
There was a problem hiding this comment.
It distracts attention. We should make separate PR for formatting.
Sorry, something went wrong.
| #pragma once | ||
|
|
||
| #include "pal.h" | ||
|
|
There was a problem hiding this comment.
Extra line.
Sorry, something went wrong.
There was a problem hiding this comment.
Discarded.
Sorry, something went wrong.
| @@ -0,0 +1,48 @@ | |||
| //! @file issamefilesystemitem.cpp | |||
| //! @author Jeff Bienstadt <v-jebien@microsoft.com> | |||
| //! @brief returns if two paths ultimately point to the same filesystem object | |||
There was a problem hiding this comment.
returns what?
Below the same.
Sorry, something went wrong.
There was a problem hiding this comment.
Please correct this.
Sorry, something went wrong.
|
|
||
| #include "getstat.h" | ||
| #include "issamefilesystemitem.h" | ||
|
|
There was a problem hiding this comment.
Extra line.
Sorry, something went wrong.
There was a problem hiding this comment.
Discarded.
Sorry, something went wrong.
|
Ilya (@iSazonov) In response to your review:
$pathExists = Test-Path $testCase.Destaination Remove-Item -Path $testCase.Destination -Force -ErrorAction SilentlyContinue $pathExists | Should Be $true
|
Sorry, something went wrong.
We don't test Windows behavior, we test PowerShell behavior. So the tests is the same for elevated and non-elevated sessions. In other words if you perform these tests with RequireAdminOnWindows, we will not miss any bug. So we can safely put RequireAdminOnWindows tag. Unix tests is not skipped if RequireAdminOnWindows present!
Based on my comments we can use this.
My suggesion is AfterEach not AfterAll. The Remove-Item is in foreach and it is executed for every test case.
I agree with using current pattern. |
Sorry, something went wrong.
| var access = FileAccess.Read; | ||
| var share = FileShare.Read; | ||
| var creation = FileMode.Open; | ||
| var attributes = FileAttributes.BackupSemantics | FileAttributes.PosixSemantics; |
There was a problem hiding this comment.
Please clarify - do we really need PosixSemantics here?
Sorry, something went wrong.
There was a problem hiding this comment.
That's for if/when we find ourselves in running in a Windows environment in which case-sensitivity has been turned on. Since the purpose of the function is to see if two files/directories are the same, it made sense to me to give it every advantage in making a correct assessment.
Sorry, something went wrong.
|
Ilya (@iSazonov) I've re-worked the structure of the tests. |
Sorry, something went wrong.
|
The Travis CI build failure puzzles me. It appears to have succeeded on Linux but failed on OS X. It appears that the offending line is Remove-Item -Path $destinationPath -Force -ErrorAction SilentlyContinue and it looks to me like it's ignoring the -ErrorAction SilentlyContinue part. Have I missed something? |
Sorry, something went wrong.
|
jeffbi That error seems to indicate a bug in the product code. The error string is from FileSystemProviderStrings.resx: <data name="ItemDoesNotExist" xml:space="preserve">
<value>An object at the specified path {0} does not exist.</value>
</data>
It looks to me an exception with this resource string got thrown. Searching where this resource string is used in code might lead you somewhere. |
Sorry, something went wrong.
There was a problem hiding this comment.
Sorry, something went wrong.
| BeforeAll { | ||
| # In Windows, only Administrators can create symbolic links. | ||
| # In Unix, anyone can. | ||
| function CanMakeSymlink |
There was a problem hiding this comment.
This is unneeded function because RequireAdminOnWindows ensures elevated rights.
Sorry, something went wrong.
There was a problem hiding this comment.
Function removed, along with use of $canSymLink
Sorry, something went wrong.
| @@ -280,7 +277,8 @@ Describe "Copy-Item can avoid copying an item onto itself" -Tags "CI" { | |||
| # Names of files, directories, and links we'll be using to test | |||
There was a problem hiding this comment.
This comment is obvious and useless. Please remove.
Sorry, something went wrong.
There was a problem hiding this comment.
Fixed.
Sorry, something went wrong.
| $junctionToOther = "$subDir/junction-to-other" | ||
|
|
||
| # Set up our directories and links | ||
| # Set up our files, directories, links |
There was a problem hiding this comment.
This comment is obvious and useless. Please remove.
Sorry, something went wrong.
There was a problem hiding this comment.
Fixed.
Sorry, something went wrong.
| SelfCopyExpected = $true | ||
| else | ||
| { | ||
| Copy-Item -Path $sourcePath -Destination $destinationPath -ErrorAction SilentlyContinue | ShouldBeErrorId "CopyError,Microsoft.PowerShell.Commands.CopyItemCommand" |
There was a problem hiding this comment.
We cannot use -ErrorAction SilentlyContinue with ShouldBeErrorId and we should use script block:
{ Copy-Item -Path $sourcePath -Destination $destinationPath -ErrorAction Stop } | ShouldBeErrorId "CopyError,Microsoft.PowerShell.Commands.CopyItemCommand"
Sorry, something went wrong.
| { | ||
| Copy-Item -Path $sourcePath -Destination $destinationPath -ErrorAction SilentlyContinue | ShouldBeErrorId "CopyError,Microsoft.PowerShell.Commands.CopyItemCommand" | ||
| $_.Exception | Should BeOfType System.IO.IOException | ||
| $_.Exception.Data[$selfCopyKey] | Should Not Be $null |
There was a problem hiding this comment.
The template is:
$exc = {
{ Copy-Item -Path $sourcePath -Destination $destinationPath -ErrorAction Stop } | ShouldBeErrorId "CopyError,Microsoft.PowerShell.Commands.CopyItemCommand"
}
$exc.Exception.Data[$selfCopyKey] | Should Not Be $null
Sorry, something went wrong.
There was a problem hiding this comment.
I've changed the test code to use $Error[0] rather than $_. I'll gladly update to use your template when ShouldBeErrorId returns something other than Boolean.
Sorry, something went wrong.
| } | ||
| Context "Copy-Item avoids copying an item onto itself" { | ||
| BeforeAll { | ||
| # Set up our test cases |
There was a problem hiding this comment.
The same about comment.
Sorry, something went wrong.
|
Dongbo Wang (@daxian-dbw) Thanks for the suggestion. I'll take a look tomorrow. It's odd because I've run the Pester tests on all three platforms, and run the Remove-Item with -ErrorAction SilentlyContinue alone, and they all work. |
Sorry, something went wrong.
| $isCaseSensitive = $IsLinux | ||
| $canSymlink = CanMakeSymlink | ||
| $canDirSymLink = $IsWindows -And (CanMakeSymlink) | ||
| $canDirSymLink = $IsWindows |
There was a problem hiding this comment.
It is not used and can be removed.
Sorry, something went wrong.
| # The source and destination paths must exist. | ||
| # If either do not, it's because they could not be created in the BeforeAll block | ||
| # This is not a test failure, but rather a precondition failure. | ||
| if ((-Not (Test-Path -Path $Source)) -or (-Not (Test-Path -Path $Destination))) |
There was a problem hiding this comment.
Please clarify 'ShouldBeErrorId' below don't fail if the items don't exist?
If failed please remove the "if-return".
If not failed we should replace the if-return with Should.
Sorry, something went wrong.
There was a problem hiding this comment.
Removed if for source file existence.
Sorry, something went wrong.
|
Ilya (@iSazonov) Can you look this over please? |
Sorry, something went wrong.
| ) | ||
|
|
||
| # Junctions and directory symbolic links are Windows and NTFS only | ||
| if ($IsWindows) |
There was a problem hiding this comment.
Oh, we shouldn't skip tests silently 😕
Maybe define the test body (below in "It" block) as function and make two "It" blocks (second "skip on non-Windows")?
Sorry, something went wrong.
There was a problem hiding this comment.
Done.
Sorry, something went wrong.
Sorry, something went wrong.
Revise comments in C++ code.
|
C++ comments updated |
Sorry, something went wrong.
|
jeffbi I don't see last commit (with C++) |
Sorry, something went wrong.
|
Thanks! I see now. LGTM. |
Sorry, something went wrong.
|
Ilya (@iSazonov) Thanks for the review! 👍 |
Sorry, something went wrong.
|
jeffbi Do you specifically choose a work with the most sophisticated tests? 😄 |
Sorry, something went wrong.
|
jeffbi Ilya (@iSazonov) This is awesome!!! This is not a trivial issue to resolve, thank you both very much for the great fix and the thorough review discussion! |
Sorry, something went wrong.
…ointing the same file (PowerShell#3441) Rather than relying on case-insensitive string compares of source and destination paths, use operating system calls to determine whether two paths refer to the same file. This solves not only the case-insensitivity issue but also allows the cmdlet to operate properly if the destination is a hard or symbolic link to the source. The Windows side is implemented in C#. The Unix side is implemented partially in native code.
| Back | FazBrowse Home | New Git URL |
Fix #1930.
Rather than relying on case-insensitive string compares of source and destination paths, use operating system calls to determine whether two paths refer to the same file. This solves not only the case-insensitivity issue but also allows the cmdlet to operate properly if the destination is a hard or symbolic link to the source.
The Windows side is implemented in C#. The Unix side is implemented partially in native code.