Clean up CreateSymLink

This commit is contained in:
Andrew Schwartzmeyer
2016-10-14 15:42:58 -07:00
parent bdfe69355f
commit 0ce5575f57
7 changed files with 40 additions and 107 deletions
@@ -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)
{
+7 -73
View File
@@ -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);
}
+1 -1
View File
@@ -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
+13 -20
View File
@@ -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);
}
+1 -1
View File
@@ -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"
}
}
}