From 3a43126a2ea163f38c8d02c8177c79e954576ec6 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Sat, 9 Apr 2016 18:23:45 -0700 Subject: [PATCH] Allow creation of symlink to non-existent target This action is completely valid on both Windows and Linux (and OS X) operating systems; tested with `mklink` and `ln -s` respectively. Note that targets for hard links must exist, thus we check specifically for symbolic links. Both the path globber in session state and the `New-Item` implementation needed to be fixed to allow the target not to exist. Resolves #801. Also enable symbolic link tests on Windows. --- .../engine/SessionStateContainer.cs | 5 ++++- .../namespaces/FileSystemProvider.cs | 7 ++++++- test/powershell/New-Item.Tests.ps1 | 15 +++++++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/System.Management.Automation/engine/SessionStateContainer.cs b/src/System.Management.Automation/engine/SessionStateContainer.cs index 3dde5cfa3fb..66246e747c3 100644 --- a/src/System.Management.Automation/engine/SessionStateContainer.cs +++ b/src/System.Management.Automation/engine/SessionStateContainer.cs @@ -3712,6 +3712,8 @@ internal void NewItem( } bool isSymbolicJunctionOrHardLink = false; + // Symbolic link targets are allowed to not exist on both Windows and Linux + bool allowNonexistingPath = false; if(type != null) { @@ -3720,6 +3722,7 @@ internal void NewItem( if (typeEvaluator.IsMatch("symboliclink") || typeEvaluator.IsMatch("junction") || typeEvaluator.IsMatch("hardlink")) { isSymbolicJunctionOrHardLink = true; + allowNonexistingPath = typeEvaluator.IsMatch("symboliclink"); } } @@ -3742,7 +3745,7 @@ internal void NewItem( var globbedTarget = Globber.GetGlobbedProviderPathsFromMonadPath( targetPath, - false, + allowNonexistingPath, context, out targetProvider, out targetProviderInstance); diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index ab14d7cf70c..79e92e995df 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -2125,9 +2125,14 @@ protected override void NewItem( bool exists = false; + // It is legal to create symbolic links to non-existing targets on + // both Windows and Linux. It is not legal to create hard links to + // non-existing targets on either Windows or Linux. try { - exists = CheckItemExists(strTargetPath, out isDirectory); + exists = (itemType == ItemType.SymbolicLink) + ? true // pretend it exists if we're making a symbolic link + : CheckItemExists(strTargetPath, out isDirectory); } catch (Exception e) { diff --git a/test/powershell/New-Item.Tests.ps1 b/test/powershell/New-Item.Tests.ps1 index f581f9be861..570b42565cb 100644 --- a/test/powershell/New-Item.Tests.ps1 +++ b/test/powershell/New-Item.Tests.ps1 @@ -104,7 +104,7 @@ Describe "New-Item" { Test-Path $FullyQualifiedFile | Should Be $false } - It "Should create a symbolic link of a file without error" -Skip:$IsWindows { + It "Should create a symbolic link of a file without error" { New-Item -Name $testfile -Path $tmpDirectory -ItemType file Test-Path $FullyQualifiedFile | Should Be $true @@ -116,7 +116,18 @@ Describe "New-Item" { $fileInfo.LinkType | Should Be "SymbolicLink" } - It "Should create a symbolic link from directory without error" -Skip:$IsWindows { + It "Should create a symbolic link to a non-existing file without error" { + $target = Join-Path $tmpDirectory "totallyBogusFile" + New-Item -ItemType SymbolicLink -Target $target -Name $testlink -Path $tmpDirectory + Test-Path $FullyQualifiedLink | Should Be $true + + $fileInfo = Get-ChildItem $FullyQualifiedLink + $fileInfo.Target | Should Be $target + Test-Path $fileInfo.Target | Should be $false + $fileInfo.LinkType | Should Be "SymbolicLink" + } + + It "Should create a symbolic link from directory without error" { New-Item -Name $testFolder -Path $tmpDirectory -ItemType directory Test-Path $FullyQualifiedFolder | Should Be $true