mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Clean up CreateSymLink
This commit is contained in:
@@ -395,7 +395,7 @@ namespace System.Management.Automation
|
||||
internal static bool NonWindowsCreateSymbolicLink(string path, string target)
|
||||
{
|
||||
// Linux doesn't care if target is a directory or not
|
||||
return Unix.NativeMethods.CreateSymLink(path, target);
|
||||
return Unix.NativeMethods.CreateSymLink(path, target) == 0;
|
||||
}
|
||||
|
||||
internal static bool NonWindowsCreateHardLink(string path, string strTargetPath)
|
||||
@@ -597,9 +597,8 @@ namespace System.Management.Automation
|
||||
internal static extern int SetDate(SetDateInfoInternal info);
|
||||
|
||||
[DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
internal static extern bool CreateSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath,
|
||||
[MarshalAs(UnmanagedType.LPStr)]string target);
|
||||
internal static extern int CreateSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath,
|
||||
[MarshalAs(UnmanagedType.LPStr)]string target);
|
||||
|
||||
[DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
internal static extern int CreateHardLink([MarshalAs(UnmanagedType.LPStr)]string filePath,
|
||||
|
||||
@@ -2208,14 +2208,11 @@ namespace Microsoft.PowerShell.Commands
|
||||
|
||||
if (itemType == ItemType.SymbolicLink)
|
||||
{
|
||||
if (Platform.IsWindows)
|
||||
{
|
||||
success = WinCreateSymbolicLink(path, strTargetPath, isDirectory);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = Platform.NonWindowsCreateSymbolicLink(path, strTargetPath);
|
||||
}
|
||||
#if UNIX
|
||||
success = Platform.NonWindowsCreateSymbolicLink(path, strTargetPath);
|
||||
#else
|
||||
success = WinCreateSymbolicLink(path, strTargetPath, isDirectory);
|
||||
#endif
|
||||
}
|
||||
else if (itemType == ItemType.HardLink)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "createsymlink.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
@@ -26,82 +27,15 @@
|
||||
//! char* is marshaled as an LPStr, which on Linux is UTF-8.
|
||||
//! @endparblock
|
||||
//!
|
||||
//! @exception errno Passes these errors via errno to GetLastError:
|
||||
//! - ERROR_INVALID_PARAMETER: parameter is not valid
|
||||
//! - ERROR_FILE_NOT_FOUND: file does not exist
|
||||
//! - ERROR_ACCESS_DENIED: access is denied
|
||||
//! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified
|
||||
//! - ERROR_INVALID_ADDRESS: attempt to access invalid address
|
||||
//! - ERROR_STOPPED_ON_SYMLINK: the operation stopped after reaching a symbolic link
|
||||
//! - ERROR_GEN_FAILURE: device attached to the system is not functioning
|
||||
//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file
|
||||
//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect
|
||||
//! - ERROR_BUFFER_OVERFLOW: file name is too long
|
||||
//! - ERROR_INVALID_FUNCTION: incorrect function
|
||||
//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters
|
||||
//!
|
||||
//! @retval boolean successful
|
||||
//! @retval 0 if successful, -1 otherwise
|
||||
//!
|
||||
|
||||
bool CreateSymLink(const char *link, const char *target)
|
||||
int32_t CreateSymLink(const char *link, const char *target)
|
||||
{
|
||||
assert(link);
|
||||
assert(target);
|
||||
|
||||
errno = 0;
|
||||
|
||||
// Check parameters
|
||||
if (!link || !target)
|
||||
{
|
||||
errno = ERROR_INVALID_PARAMETER;
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret = symlink(target, link);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
switch(errno)
|
||||
{
|
||||
case EACCES:
|
||||
errno = ERROR_ACCESS_DENIED;
|
||||
break;
|
||||
case EDQUOT:
|
||||
errno = ERROR_DISK_FULL;
|
||||
break;
|
||||
case EEXIST:
|
||||
errno = ERROR_FILE_EXISTS;
|
||||
break;
|
||||
case EFAULT:
|
||||
errno = ERROR_INVALID_ADDRESS;
|
||||
break;
|
||||
case EIO:
|
||||
errno = ERROR_GEN_FAILURE;
|
||||
break;
|
||||
case ELOOP:
|
||||
errno = ERROR_STOPPED_ON_SYMLINK;
|
||||
break;
|
||||
case ENAMETOOLONG:
|
||||
errno = ERROR_BAD_PATH_NAME;
|
||||
break;
|
||||
case ENOENT:
|
||||
errno = ERROR_FILE_NOT_FOUND;
|
||||
break;
|
||||
case ENOMEM:
|
||||
errno = ERROR_OUTOFMEMORY;
|
||||
break;
|
||||
case ENOTDIR:
|
||||
errno = ERROR_INVALID_NAME;
|
||||
break;
|
||||
case ENOSPC:
|
||||
errno = ERROR_DISK_FULL;
|
||||
break;
|
||||
case EPERM:
|
||||
errno = ERROR_GEN_FAILURE;
|
||||
break;
|
||||
default:
|
||||
errno = ERROR_INVALID_FUNCTION;
|
||||
}
|
||||
|
||||
return false;
|
||||
return symlink(target, link);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
|
||||
PAL_BEGIN_EXTERNC
|
||||
|
||||
bool CreateSymLink(const char *link, const char *target);
|
||||
int32_t CreateSymLink(const char *link, const char *target);
|
||||
|
||||
PAL_END_EXTERNC
|
||||
|
||||
@@ -39,12 +39,12 @@ protected:
|
||||
EXPECT_TRUE(dir != NULL);
|
||||
|
||||
// Create symbolic link to file
|
||||
bool ret1 = CreateSymLink(fileSymLink.c_str(), file);
|
||||
EXPECT_TRUE(ret1);
|
||||
int ret = CreateSymLink(fileSymLink.c_str(), file);
|
||||
EXPECT_EQ(0, ret);
|
||||
|
||||
// Create symbolic link to directory
|
||||
bool ret2 = CreateSymLink(dirSymLink.c_str(), dir);
|
||||
EXPECT_TRUE(ret2);
|
||||
ret = CreateSymLink(dirSymLink.c_str(), dir);
|
||||
EXPECT_EQ(0, ret);
|
||||
}
|
||||
|
||||
~CreateSymLinkTest()
|
||||
@@ -65,13 +65,6 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(CreateSymLinkTest, FilePathNameIsNull)
|
||||
{
|
||||
bool retVal = CreateSymLink(NULL, NULL);
|
||||
EXPECT_FALSE(retVal);
|
||||
EXPECT_EQ(ERROR_INVALID_PARAMETER, errno);
|
||||
}
|
||||
|
||||
TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist)
|
||||
{
|
||||
std::string invalidFile = "/tmp/symlinktest_invalidFile";
|
||||
@@ -82,8 +75,8 @@ TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist)
|
||||
unlink(invalidLink.c_str());
|
||||
|
||||
// Linux allows creation of symbolic link that points to an invalid file
|
||||
bool retVal = CreateSymLink(invalidLink.c_str(), invalidFile.c_str());
|
||||
EXPECT_TRUE(retVal);
|
||||
int ret = CreateSymLink(invalidLink.c_str(), invalidFile.c_str());
|
||||
EXPECT_EQ(0, ret);
|
||||
|
||||
std::string target = FollowSymLink(invalidLink.c_str());
|
||||
EXPECT_EQ(target, invalidFile);
|
||||
@@ -93,8 +86,8 @@ TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist)
|
||||
|
||||
TEST_F(CreateSymLinkTest, SymLinkToFile)
|
||||
{
|
||||
bool retVal = IsSymLink(fileSymLink.c_str());
|
||||
EXPECT_TRUE(retVal);
|
||||
bool ret = IsSymLink(fileSymLink.c_str());
|
||||
EXPECT_TRUE(ret);
|
||||
|
||||
std::string target = FollowSymLink(fileSymLink.c_str());
|
||||
char buffer[PATH_MAX];
|
||||
@@ -104,8 +97,8 @@ TEST_F(CreateSymLinkTest, SymLinkToFile)
|
||||
|
||||
TEST_F(CreateSymLinkTest, SymLinkToDirectory)
|
||||
{
|
||||
bool retVal = IsSymLink(dirSymLink.c_str());
|
||||
EXPECT_TRUE(retVal);
|
||||
bool ret = IsSymLink(dirSymLink.c_str());
|
||||
EXPECT_TRUE(ret);
|
||||
|
||||
std::string target = FollowSymLink(dirSymLink.c_str());
|
||||
char buffer[PATH_MAX];
|
||||
@@ -115,7 +108,7 @@ TEST_F(CreateSymLinkTest, SymLinkToDirectory)
|
||||
|
||||
TEST_F(CreateSymLinkTest, SymLinkAgain)
|
||||
{
|
||||
bool retVal = CreateSymLink(fileSymLink.c_str(), file);
|
||||
EXPECT_FALSE(retVal);
|
||||
EXPECT_EQ(ERROR_FILE_EXISTS, errno);
|
||||
int ret = CreateSymLink(fileSymLink.c_str(), file);
|
||||
EXPECT_EQ(-1, ret);
|
||||
EXPECT_EQ(EEXIST, errno);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ TEST_F(isSymLinkTest, FilePathNameDoesNotExist)
|
||||
{
|
||||
std::string invalidFile = "/tmp/symlinktest_invalidFile";
|
||||
EXPECT_FALSE(IsSymLink(invalidFile.c_str()));
|
||||
EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno);
|
||||
EXPECT_EQ(ENOENT, errno);
|
||||
}
|
||||
|
||||
TEST_F(isSymLinkTest, NormalFileIsNotSymLink)
|
||||
|
||||
@@ -171,4 +171,14 @@ Describe "New-Item with links" -Tags @('CI', 'RequireAdminOnWindows') {
|
||||
# Remove the link explicitly to avoid broken symlink issue
|
||||
Remove-Item $FullyQualifiedLink -Force
|
||||
}
|
||||
|
||||
It "Should error correctly when failing to create a symbolic link" -Skip:($IsWindows -or $IsElevated) {
|
||||
# This test expects that /sbin exists but is not writable by the user
|
||||
try {
|
||||
New-Item -ItemType SymbolicLink -Path "/sbin/powershell-test" -Target $FullyQualifiedFolder -ErrorAction Stop
|
||||
throw "Execution OK"
|
||||
} catch {
|
||||
$_.FullyQualifiedErrorId | Should Be "NewItemSymbolicLinkElevationRequired,Microsoft.PowerShell.Commands.NewItemCommand"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user