Skip to content

Commit

Permalink
Add test and copy implementation to realpath2
Browse files Browse the repository at this point in the history
  • Loading branch information
agocke committed Jul 7, 2023
1 parent 57608c3 commit c57c6fb
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 0 deletions.
25 changes: 25 additions & 0 deletions src/installer/tests/HostActivation.Tests/PortableAppActivation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,31 @@ public PortableAppActivation(SharedTestState fixture)
sharedTestState = fixture;
}

[Fact]
public void Muxer_behind_symlink()
{
var fixture = sharedTestState.PortableAppFixture_Built
.Copy();

var dotnetLoc = fixture.BuiltDotnet.DotnetExecutablePath;
var appDll = fixture.TestProject.AppDll;
var testDir = Directory.GetParent(fixture.TestProject.Location).ToString();

var exeSuffix = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : "";

using var symlink = new SymLink(Path.Combine(testDir, "dn" + exeSuffix), dotnetLoc);

var cmd = Command.Create(symlink.SrcPath, new[] { appDll })
.CaptureStdOut()
.CaptureStdErr()
.EnvironmentVariable("DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "1")
.MultilevelLookup(false); // Avoid looking at machine state by default

cmd.Execute()
.Should().Pass()
.And.HaveStdOutContaining("Hello World");
}

[Fact]
public void Muxer_activation_of_Build_Output_Portable_DLL_with_DepsJson_and_RuntimeConfig_Local_Succeeds()
{
Expand Down
1 change: 1 addition & 0 deletions src/native/corehost/hostmisc/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ namespace pal

bool touch_file(const string_t& path);
bool realpath(string_t* path, bool skip_error_logging = false);
bool fullpath(string_t* path, bool skip_error_logging = false);
bool file_exists(const string_t& path);
inline bool directory_exists(const string_t& path) { return file_exists(path); }
void readdir(const string_t& path, const string_t& pattern, std::vector<string_t>* list);
Expand Down
5 changes: 5 additions & 0 deletions src/native/corehost/hostmisc/pal.unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,11 @@ bool pal::getenv(const pal::char_t* name, pal::string_t* recv)
return (recv->length() > 0);
}

bool pal::fullpath(pal::string_t* path, bool skip_error_logging)
{
return realpath(path, skip_error_logging);
}

bool pal::realpath(pal::string_t* path, bool skip_error_logging)
{
auto resolved = ::realpath(path->c_str(), nullptr);
Expand Down
82 changes: 82 additions & 0 deletions src/native/corehost/hostmisc/pal.windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,88 @@ bool pal::clr_palstring(const char* cstr, pal::string_t* out)

// Return if path is valid and file exists, return true and adjust path as appropriate.
bool pal::realpath(string_t* path, bool skip_error_logging)
{
return fullpath(path, skip_error_logging);
}

typedef std::unique_ptr<std::remove_pointer<HANDLE>::type, decltype(&::CloseHandle)> SmartHandle;

// Like realpath, but resolves symlinks.
bool pal::realpath2(string_t* path, bool skip_error_logging)
{
if (path->empty())
{
return false;
}

// Use CreateFileW + GetFinalPathNameByHandleW to resolve symlinks

SmartHandle file(
::CreateFileW(
path->c_str(),
0, // Querying only
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr, // default security
OPEN_EXISTING, // existing file
FILE_ATTRIBUTE_NORMAL, // normal file
nullptr), // No attribute template
&::CloseHandle);

char_t buf[MAX_PATH];
size_t size;

if (file.get() == INVALID_HANDLE_VALUE)
{
// If we get "access denied" that may mean the path represents a directory.
// Even if not, we can fall back to GetFullPathNameW, which doesn't require a HANDLE

auto error = ::GetLastError();
file.release();
if (ERROR_ACCESS_DENIED != error)
{
goto invalidPath;
}
}
else
{
size = ::GetFinalPathNameByHandleW(file.get(), buf, MAX_PATH, FILE_NAME_NORMALIZED);
// If size is 0, this call failed. Fall back to GetFullPathNameW, below
if (size != 0)
{
string_t str;
if (size < MAX_PATH)
{
str.assign(buf);
}
else
{
str.resize(size, 0);
size = ::GetFinalPathNameByHandleW(file.get(), (LPWSTR)str.data(), static_cast<uint32_t>(size), FILE_NAME_NORMALIZED);
assert(size <= str.size());

if (size == 0)
{
goto invalidPath;
}
}

// Remove the \\?\ prefix, unless it is necessary or was already there
if (LongFile::IsExtended(str) && !LongFile::IsExtended(*path) &&
!LongFile::ShouldNormalize(str.substr(LongFile::ExtendedPrefix.size())))
{
str.erase(0, LongFile::ExtendedPrefix.size());
}

*path = str;
return true;
}
}

// If the above fails, fall back to fullpath
return fullpath(path, skip_error_logging);
}

bool pal::fullpath(string_t* path, bool skip_error_logging)
{
if (path->empty())
{
Expand Down

0 comments on commit c57c6fb

Please sign in to comment.