Skip to content

Commit 0ce5575

Browse files
committed
Clean up CreateSymLink
1 parent bdfe693 commit 0ce5575

7 files changed

Lines changed: 40 additions & 107 deletions

File tree

src/System.Management.Automation/CoreCLR/CorePsPlatform.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ internal static string NonWindowsInternalGetLinkType(FileSystemInfo fileInfo)
395395
internal static bool NonWindowsCreateSymbolicLink(string path, string target)
396396
{
397397
// Linux doesn't care if target is a directory or not
398-
return Unix.NativeMethods.CreateSymLink(path, target);
398+
return Unix.NativeMethods.CreateSymLink(path, target) == 0;
399399
}
400400

401401
internal static bool NonWindowsCreateHardLink(string path, string strTargetPath)
@@ -597,9 +597,8 @@ internal static class NativeMethods
597597
internal static extern int SetDate(SetDateInfoInternal info);
598598

599599
[DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)]
600-
[return: MarshalAs(UnmanagedType.I1)]
601-
internal static extern bool CreateSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath,
602-
[MarshalAs(UnmanagedType.LPStr)]string target);
600+
internal static extern int CreateSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath,
601+
[MarshalAs(UnmanagedType.LPStr)]string target);
603602

604603
[DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)]
605604
internal static extern int CreateHardLink([MarshalAs(UnmanagedType.LPStr)]string filePath,

src/System.Management.Automation/namespaces/FileSystemProvider.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,14 +2208,11 @@ protected override void NewItem(
22082208

22092209
if (itemType == ItemType.SymbolicLink)
22102210
{
2211-
if (Platform.IsWindows)
2212-
{
2213-
success = WinCreateSymbolicLink(path, strTargetPath, isDirectory);
2214-
}
2215-
else
2216-
{
2217-
success = Platform.NonWindowsCreateSymbolicLink(path, strTargetPath);
2218-
}
2211+
#if UNIX
2212+
success = Platform.NonWindowsCreateSymbolicLink(path, strTargetPath);
2213+
#else
2214+
success = WinCreateSymbolicLink(path, strTargetPath, isDirectory);
2215+
#endif
22192216
}
22202217
else if (itemType == ItemType.HardLink)
22212218
{

src/libpsl-native/src/createsymlink.cpp

Lines changed: 7 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "createsymlink.h"
66

7+
#include <assert.h>
78
#include <errno.h>
89
#include <unistd.h>
910
#include <string>
@@ -26,82 +27,15 @@
2627
//! char* is marshaled as an LPStr, which on Linux is UTF-8.
2728
//! @endparblock
2829
//!
29-
//! @exception errno Passes these errors via errno to GetLastError:
30-
//! - ERROR_INVALID_PARAMETER: parameter is not valid
31-
//! - ERROR_FILE_NOT_FOUND: file does not exist
32-
//! - ERROR_ACCESS_DENIED: access is denied
33-
//! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified
34-
//! - ERROR_INVALID_ADDRESS: attempt to access invalid address
35-
//! - ERROR_STOPPED_ON_SYMLINK: the operation stopped after reaching a symbolic link
36-
//! - ERROR_GEN_FAILURE: device attached to the system is not functioning
37-
//! - ERROR_NO_SUCH_USER: there was no corresponding entry in the utmp-file
38-
//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect
39-
//! - ERROR_BUFFER_OVERFLOW: file name is too long
40-
//! - ERROR_INVALID_FUNCTION: incorrect function
41-
//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters
42-
//!
43-
//! @retval boolean successful
30+
//! @retval 0 if successful, -1 otherwise
4431
//!
4532

46-
bool CreateSymLink(const char *link, const char *target)
33+
int32_t CreateSymLink(const char *link, const char *target)
4734
{
48-
errno = 0;
49-
50-
// Check parameters
51-
if (!link || !target)
52-
{
53-
errno = ERROR_INVALID_PARAMETER;
54-
return false;
55-
}
35+
assert(link);
36+
assert(target);
5637

57-
int ret = symlink(target, link);
58-
59-
if (ret == 0)
60-
{
61-
return true;
62-
}
63-
64-
switch(errno)
65-
{
66-
case EACCES:
67-
errno = ERROR_ACCESS_DENIED;
68-
break;
69-
case EDQUOT:
70-
errno = ERROR_DISK_FULL;
71-
break;
72-
case EEXIST:
73-
errno = ERROR_FILE_EXISTS;
74-
break;
75-
case EFAULT:
76-
errno = ERROR_INVALID_ADDRESS;
77-
break;
78-
case EIO:
79-
errno = ERROR_GEN_FAILURE;
80-
break;
81-
case ELOOP:
82-
errno = ERROR_STOPPED_ON_SYMLINK;
83-
break;
84-
case ENAMETOOLONG:
85-
errno = ERROR_BAD_PATH_NAME;
86-
break;
87-
case ENOENT:
88-
errno = ERROR_FILE_NOT_FOUND;
89-
break;
90-
case ENOMEM:
91-
errno = ERROR_OUTOFMEMORY;
92-
break;
93-
case ENOTDIR:
94-
errno = ERROR_INVALID_NAME;
95-
break;
96-
case ENOSPC:
97-
errno = ERROR_DISK_FULL;
98-
break;
99-
case EPERM:
100-
errno = ERROR_GEN_FAILURE;
101-
break;
102-
default:
103-
errno = ERROR_INVALID_FUNCTION;
104-
}
38+
errno = 0;
10539

106-
return false;
40+
return symlink(target, link);
10741
}

src/libpsl-native/src/createsymlink.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66

77
PAL_BEGIN_EXTERNC
88

9-
bool CreateSymLink(const char *link, const char *target);
9+
int32_t CreateSymLink(const char *link, const char *target);
1010

1111
PAL_END_EXTERNC

src/libpsl-native/test/test-createsymlink.cpp

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ class CreateSymLinkTest : public ::testing::Test
3939
EXPECT_TRUE(dir != NULL);
4040

4141
// Create symbolic link to file
42-
bool ret1 = CreateSymLink(fileSymLink.c_str(), file);
43-
EXPECT_TRUE(ret1);
42+
int ret = CreateSymLink(fileSymLink.c_str(), file);
43+
EXPECT_EQ(0, ret);
4444

4545
// Create symbolic link to directory
46-
bool ret2 = CreateSymLink(dirSymLink.c_str(), dir);
47-
EXPECT_TRUE(ret2);
46+
ret = CreateSymLink(dirSymLink.c_str(), dir);
47+
EXPECT_EQ(0, ret);
4848
}
4949

5050
~CreateSymLinkTest()
@@ -65,13 +65,6 @@ class CreateSymLinkTest : public ::testing::Test
6565
}
6666
};
6767

68-
TEST_F(CreateSymLinkTest, FilePathNameIsNull)
69-
{
70-
bool retVal = CreateSymLink(NULL, NULL);
71-
EXPECT_FALSE(retVal);
72-
EXPECT_EQ(ERROR_INVALID_PARAMETER, errno);
73-
}
74-
7568
TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist)
7669
{
7770
std::string invalidFile = "/tmp/symlinktest_invalidFile";
@@ -82,8 +75,8 @@ TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist)
8275
unlink(invalidLink.c_str());
8376

8477
// Linux allows creation of symbolic link that points to an invalid file
85-
bool retVal = CreateSymLink(invalidLink.c_str(), invalidFile.c_str());
86-
EXPECT_TRUE(retVal);
78+
int ret = CreateSymLink(invalidLink.c_str(), invalidFile.c_str());
79+
EXPECT_EQ(0, ret);
8780

8881
std::string target = FollowSymLink(invalidLink.c_str());
8982
EXPECT_EQ(target, invalidFile);
@@ -93,8 +86,8 @@ TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist)
9386

9487
TEST_F(CreateSymLinkTest, SymLinkToFile)
9588
{
96-
bool retVal = IsSymLink(fileSymLink.c_str());
97-
EXPECT_TRUE(retVal);
89+
bool ret = IsSymLink(fileSymLink.c_str());
90+
EXPECT_TRUE(ret);
9891

9992
std::string target = FollowSymLink(fileSymLink.c_str());
10093
char buffer[PATH_MAX];
@@ -104,8 +97,8 @@ TEST_F(CreateSymLinkTest, SymLinkToFile)
10497

10598
TEST_F(CreateSymLinkTest, SymLinkToDirectory)
10699
{
107-
bool retVal = IsSymLink(dirSymLink.c_str());
108-
EXPECT_TRUE(retVal);
100+
bool ret = IsSymLink(dirSymLink.c_str());
101+
EXPECT_TRUE(ret);
109102

110103
std::string target = FollowSymLink(dirSymLink.c_str());
111104
char buffer[PATH_MAX];
@@ -115,7 +108,7 @@ TEST_F(CreateSymLinkTest, SymLinkToDirectory)
115108

116109
TEST_F(CreateSymLinkTest, SymLinkAgain)
117110
{
118-
bool retVal = CreateSymLink(fileSymLink.c_str(), file);
119-
EXPECT_FALSE(retVal);
120-
EXPECT_EQ(ERROR_FILE_EXISTS, errno);
111+
int ret = CreateSymLink(fileSymLink.c_str(), file);
112+
EXPECT_EQ(-1, ret);
113+
EXPECT_EQ(EEXIST, errno);
121114
}

src/libpsl-native/test/test-issymlink.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ TEST_F(isSymLinkTest, FilePathNameDoesNotExist)
6565
{
6666
std::string invalidFile = "/tmp/symlinktest_invalidFile";
6767
EXPECT_FALSE(IsSymLink(invalidFile.c_str()));
68-
EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno);
68+
EXPECT_EQ(ENOENT, errno);
6969
}
7070

7171
TEST_F(isSymLinkTest, NormalFileIsNotSymLink)

test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,4 +171,14 @@ Describe "New-Item with links" -Tags @('CI', 'RequireAdminOnWindows') {
171171
# Remove the link explicitly to avoid broken symlink issue
172172
Remove-Item $FullyQualifiedLink -Force
173173
}
174+
175+
It "Should error correctly when failing to create a symbolic link" -Skip:($IsWindows -or $IsElevated) {
176+
# This test expects that /sbin exists but is not writable by the user
177+
try {
178+
New-Item -ItemType SymbolicLink -Path "/sbin/powershell-test" -Target $FullyQualifiedFolder -ErrorAction Stop
179+
throw "Execution OK"
180+
} catch {
181+
$_.FullyQualifiedErrorId | Should Be "NewItemSymbolicLinkElevationRequired,Microsoft.PowerShell.Commands.NewItemCommand"
182+
}
183+
}
174184
}

0 commit comments

Comments
 (0)