-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Replace string-compare-based test for copying to same file with more … #3441
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
Changes from all commits
d970809
3263893
a1e905b
9fff05b
8814054
19702a0
07b1594
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
//! @file issamefilesystemitem.cpp | ||
//! @author Jeff Bienstadt <v-jebien@microsoft.com> | ||
//! @brief Determines whether two paths ultimately point to the same filesystem object | ||
|
||
#include "getstat.h" | ||
#include "issamefilesystemitem.h" | ||
|
||
#include <assert.h> | ||
#include <sys/types.h> | ||
#include <sys/stat.h> | ||
#include <unistd.h> | ||
|
||
//! @brief Returns a boolean value indicating whether two paths ultimately refer to the same file or directory. | ||
//! | ||
//! IsSameFileSystemItem | ||
//! | ||
//! @param[in] path_one | ||
//! @parblock | ||
//! A pointer to the buffer that contains the first path. | ||
//! | ||
//! char* is marshaled as an LPStr, which on Linux is UTF-8. | ||
//! @endparblock | ||
//! | ||
//! @param[in] path_two | ||
//! @parblock | ||
//! A pointer to the buffer that contains the second path. | ||
//! | ||
//! char* is marshaled as an LPStr, which on Linux is UTF-8. | ||
//! @endparblock | ||
//! | ||
//! @retval true if both paths point to the same filesystem object, | ||
//! false otherwise | ||
//! | ||
bool IsSameFileSystemItem(const char* path_one, const char* path_two) | ||
{ | ||
assert(path_one); | ||
assert(path_two); | ||
|
||
struct stat buf_1; | ||
struct stat buf_2; | ||
|
||
if (GetStat(path_one, &buf_1) == 0 && GetStat(path_two, &buf_2) == 0) | ||
{ | ||
return buf_1.st_dev == buf_2.st_dev && buf_1.st_ino == buf_2.st_ino; | ||
} | ||
|
||
return false; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#pragma once | ||
|
||
#include "pal.h" | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extra line. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Discarded. |
||
#include <stdbool.h> | ||
|
||
PAL_BEGIN_EXTERNC | ||
|
||
bool IsSameFileSystemItem(const char* path_one, const char* path_two); | ||
|
||
PAL_END_EXTERNC |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -246,6 +246,157 @@ Describe "Basic FileSystem Provider Tests" -Tags "CI" { | |
} | ||
} | ||
|
||
|
||
Describe "Copy-Item can avoid copying an item onto itself" -Tags "CI", "RequireAdminOnWindows" { | ||
BeforeAll { | ||
# For now, we'll assume the tests are running the platform's | ||
# native filesystem, in its default mode | ||
$isCaseSensitive = $IsLinux | ||
|
||
# The name of the key in an exception's Data dictionary when an | ||
# attempt is made to copy an item onto itself. | ||
$selfCopyKey = "SelfCopy" | ||
|
||
$TestDrive = "TestDrive:" | ||
$subDir = "$TestDrive/sub" | ||
$otherSubDir = "$TestDrive/other-sub" | ||
$fileName = "file.txt" | ||
$filePath = "$TestDrive/$fileName" | ||
$otherFileName = "other-file" | ||
$otherFile = "$otherSubDir/$otherFileName" | ||
$symToOther = "$subDir/sym-to-other" | ||
$secondSymToOther = "$subDir/another-sym-to-other" | ||
$symToSym = "$subDir/sym-to-sym-to-other" | ||
$symToOtherFile = "$subDir/sym-to-other-file" | ||
$hardToOtherFile = "$subDir/hard-to-other-file" | ||
$symdToOther = "$subDir/symd-to-other" | ||
$junctionToOther = "$subDir/junction-to-other" | ||
|
||
New-Item -ItemType File $filePath -Value "stuff" >$null | ||
New-Item -ItemType Directory $subDir >$null | ||
New-Item -ItemType Directory $otherSubDir >$null | ||
New-Item -ItemType File $otherFile -Value "some text" >$null | ||
New-Item -ItemType SymbolicLink $symToOther -Value $otherSubDir >$null | ||
New-Item -ItemType SymbolicLink $secondSymToOther -Value $otherSubDir >$null | ||
New-Item -ItemType SymbolicLink $symToSym -Value $symToOther >$null | ||
New-Item -ItemType SymbolicLink $symToOtherFile -Value $otherFile >$null | ||
New-Item -ItemType HardLink $hardToOtherFile -Value $otherFile >$null | ||
|
||
if ($IsWindows) | ||
{ | ||
New-Item -ItemType Junction $junctionToOther -Value $otherSubDir >$null | ||
New-Item -ItemType SymbolicLink $symdToOther -Value $otherSubDir >$null | ||
} | ||
} | ||
|
||
Context "Copy-Item using different case (on case-sensitive file systems)" { | ||
BeforeEach { | ||
$sourcePath = $filePath | ||
$destinationPath = "$TestDrive/" + $fileName.Toupper() | ||
} | ||
AfterEach { | ||
Remove-Item -Path $destinationPath -ErrorAction SilentlyContinue | ||
} | ||
|
||
It "Copy-Item can copy to file name differing only by case" { | ||
if ($isCaseSensitive) | ||
{ | ||
Copy-Item -Path $sourcePath -Destination $destinationPath -ErrorAction SilentlyContinue | Should Be $null | ||
Test-Path -Path $destinationPath | Should Be $true | ||
} | ||
else | ||
{ | ||
{ Copy-Item -Path $sourcePath -Destination $destinationPath -ErrorAction Stop } | ShouldBeErrorId "CopyError,Microsoft.PowerShell.Commands.CopyItemCommand" | ||
$Error[0].Exception | Should BeOfType System.IO.IOException | ||
$Error[0].Exception.Data[$selfCopyKey] | Should Not Be $null | ||
} | ||
} | ||
} | ||
|
||
Context "Copy-Item avoids copying an item onto itself" { | ||
BeforeAll { | ||
$testCases = @( | ||
@{ | ||
Name = "Copy to same path" | ||
Source = $otherFile | ||
Destination = $otherFile | ||
} | ||
@{ | ||
Name = "Copy hard link" | ||
Source = $hardToOtherFile | ||
Destination = $otherFile | ||
} | ||
@{ | ||
Name = "Copy hard link, reversed" | ||
Source = $otherFile | ||
Destination = $hardToOtherFile | ||
} | ||
@{ | ||
Name = "Copy symbolic link to target" | ||
Source = $symToOtherFile | ||
Destination = $otherFile | ||
} | ||
@{ | ||
Name = "Copy symbolic link to symbolic link with same target" | ||
Source = $secondSymToOther | ||
Destination = $symToOther | ||
} | ||
@{ | ||
Name = "Copy through chain of symbolic links" | ||
Source = $symToSym | ||
Destination = $otherSubDir | ||
} | ||
) | ||
|
||
# Junctions and directory symbolic links are Windows and NTFS only | ||
$windowsTestCases = @( | ||
@{ | ||
Name = "Copy junction to target" | ||
Source = $junctionToOther | ||
Destination = $otherSubDir | ||
} | ||
@{ | ||
Name = "Copy directory symbolic link to target" | ||
Source = $symdToOther | ||
Destination = $otherSubDir | ||
} | ||
) | ||
|
||
function TestSelfCopy | ||
{ | ||
Param ( | ||
[string]$Source, | ||
[string]$Destination | ||
) | ||
|
||
{ Copy-Item -Path $Source -Destination $Destination -ErrorAction Stop } | ShouldBeErrorId "CopyError,Microsoft.PowerShell.Commands.CopyItemCommand" | ||
$Error[0].Exception | Should BeOfType System.IO.IOException | ||
$Error[0].Exception.Data[$selfCopyKey] | Should Not Be $null | ||
} | ||
} | ||
|
||
It "<Name>" -TestCases $testCases { | ||
Param ( | ||
[string]$Name, | ||
[string]$Source, | ||
[string]$Destination | ||
) | ||
|
||
TestSelfCopy $Source $Destination | ||
} | ||
|
||
It "<Name>" -TestCases $windowsTestCases -Skip:(-not $IsWindows) { | ||
Param ( | ||
[string]$Name, | ||
[string]$Source, | ||
[string]$Destination | ||
) | ||
|
||
TestSelfCopy $Source $Destination | ||
} | ||
} | ||
} | ||
|
||
Describe "Extended FileSystem Item/Content Cmdlet Provider Tests" -Tags "Feature" { | ||
BeforeAll { | ||
$testDir = "testDir" | ||
|
@@ -629,14 +780,13 @@ Describe "Extended FileSystem Path/Location Cmdlet Provider Tests" -Tags "Featur | |
$result = Split-Path -Path $level1_0Full -Leaf | ||
$result | Should Be $level1_0 | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It distracts attention. We should make separate PR for formatting. |
||
It 'Validate LeafBase' { | ||
$result = Split-Path -Path "$level2_1Full$fileExt" -LeafBase | ||
$result | Should Be $level2_1 | ||
} | ||
|
||
It 'Validate LeafBase is not over-zealous' { | ||
|
||
$result = Split-Path -Path "$level2_1Full$fileExt$fileExt" -LeafBase | ||
$result | Should Be "$level2_1$fileExt" | ||
} | ||
|
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.
Please clarify - do we really need PosixSemantics here?
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.
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.