Skip to content

Commit

Permalink
Merge pull request #2196 from Sonicadvance1/optimize_symlink_following
Browse files Browse the repository at this point in the history
Linux: Improve performance of hot paths in path searching
  • Loading branch information
lioncash committed Dec 5, 2022
2 parents 1dd5642 + 50cf74d commit 66e0d46
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 12 deletions.
12 changes: 7 additions & 5 deletions Source/Tests/ELFCodeLoader2.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,19 +180,21 @@ class ELFCodeLoader2 final : public FEXCore::CodeLoader {

static std::string ResolveRootfsFile(std::string const &File, std::string RootFS) {
// If the path is relative then just run that
if (std::filesystem::path(File).is_relative()) {
if (File[0] != '/') {
return File;
}

std::string RootFSLink = RootFS + File;

while (std::filesystem::is_symlink(RootFSLink)) {
char Filename[PATH_MAX];
while(FEX::HLE::IsSymlink(RootFSLink)) {
// Do some special handling if the RootFS's linker is a symlink
// Ubuntu's rootFS by default provides an absolute location symlink to the linker
// Resolve this around back to the rootfs
auto SymlinkTarget = std::filesystem::read_symlink(RootFSLink);
if (SymlinkTarget.is_absolute()) {
RootFSLink = RootFS + SymlinkTarget.string();
auto SymlinkSize = FEX::HLE::GetSymlink(RootFSLink, Filename, PATH_MAX - 1);
if (SymlinkSize > 0 && Filename[0] == '/') {
RootFSLink = RootFS;
RootFSLink += std::string_view(Filename, SymlinkSize);
}
else {
break;
Expand Down
2 changes: 1 addition & 1 deletion Source/Tests/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@ namespace FEX::EmulatedFile {
}

std::error_code ec;
bool exists = std::filesystem::exists(Path, ec);
bool exists = access(Path.c_str(), F_OK) == 0;
if (ec) {
return -1;
}
Expand Down
13 changes: 7 additions & 6 deletions Source/Tests/LinuxSyscalls/FileManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,6 @@ FileManager::~FileManager() {
}

std::string FileManager::GetEmulatedPath(const char *pathname, bool FollowSymlink) {
auto RootFSPath = LDPath();
if (!pathname || // If no pathname
pathname[0] != '/' || // If relative
strcmp(pathname, "/") == 0) { // If we are getting root
Expand All @@ -367,17 +366,19 @@ std::string FileManager::GetEmulatedPath(const char *pathname, bool FollowSymlin
return thunkOverlay->second;
}

auto RootFSPath = LDPath();
if (RootFSPath.empty()) { // If RootFS doesn't exist
return {};
}

std::string Path = RootFSPath + pathname;
if (FollowSymlink) {
std::error_code ec;
while(std::filesystem::is_symlink(Path, ec)) {
auto SymlinkTarget = std::filesystem::read_symlink(Path);
if (SymlinkTarget.is_absolute()) {
Path = RootFSPath + SymlinkTarget.string();
char Filename[PATH_MAX];
while(FEX::HLE::IsSymlink(Path)) {
auto SymlinkSize = FEX::HLE::GetSymlink(Path, Filename, PATH_MAX - 1);
if (SymlinkSize > 0 && Filename[0] == '/') {
Path = RootFSPath;
Path += std::string_view(Filename, SymlinkSize);
}
else {
break;
Expand Down
13 changes: 13 additions & 0 deletions Source/Tests/LinuxSyscalls/FileManagement.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ tags: LinuxSyscalls|common
#include <stddef.h>
#include <string>
#include <sys/stat.h>
#include <unistd.h>
#include <vector>

#include <unordered_map>
Expand All @@ -27,6 +28,18 @@ struct Context;
}

namespace FEX::HLE {
[[maybe_unused]]
static bool IsSymlink(const std::string &Filename) {
// Checks to see if a filepath is a symlink.
struct stat Buffer{};
int Result = lstat(Filename.c_str(), &Buffer);
return Result == 0 && S_ISLNK(Buffer.st_mode);
}

[[maybe_unused]]
static ssize_t GetSymlink(const std::string &Filename, char *ResultBuffer, size_t ResultBufferSize) {
return readlink(Filename.c_str(), ResultBuffer, ResultBufferSize);
}

struct open_how;

Expand Down

0 comments on commit 66e0d46

Please sign in to comment.