correct handling for placeholders @loader_path and @executable_path by really relying on the directory of the according file (and not the filename itself)

This commit is contained in:
Konrad Windszus 2016-12-04 16:32:17 +01:00
parent 66202abd66
commit 2004b7a99c
7 changed files with 114 additions and 122 deletions

View File

@ -27,7 +27,7 @@ DynamicLoader::EnvironmentPathVariable::EnvironmentPathVariable(const char* home
if (envValue) {
values = envValue;
}
if (!values.empty()) {
std::stringstream v(values);
std::string item;
@ -41,7 +41,7 @@ DynamicLoader::EnvironmentPathVariable::EnvironmentPathVariable(const char* home
void DynamicLoader::EnvironmentPathVariable::setPaths(const StringList& paths) {
this->paths = paths;
for (StringList::iterator it = this->paths.begin(); it!=this->paths.end(); ++it) {
replaceHomeDirectory(*it);
}
@ -117,7 +117,7 @@ DynamicLoader::DynamicLoader()
for (unsigned int i=0; i < NumEnvironmentVariables; i++) {
environmentVariables[i] = EnvironmentPathVariable(homePath, ENVIRONMENT_VARIABLE_NAMES[i], ENVIRONMENT_VARIABLE_DEFAULT_VALUES[i]);
}
}
DynamicLoader::~DynamicLoader() {
@ -142,7 +142,7 @@ std::string DynamicLoader::replacePlaceholder(const std::string& name, const Mac
if (name.find(PLACEHOLDERS[ExecutablePath]) == 0) {
resolvedName.replace(0, strlen(PLACEHOLDERS[ExecutablePath]), architecture->getFile()->getExecutablePath());
} else if (name.find(PLACEHOLDERS[LoaderPath]) == 0) {
resolvedName.replace(0, strlen(PLACEHOLDERS[LoaderPath]), architecture->getFile()->getPath());
resolvedName.replace(0, strlen(PLACEHOLDERS[LoaderPath]), architecture->getFile()->getDirectory());
}
return resolvedName;
}
@ -156,13 +156,13 @@ std::string DynamicLoader::getPathname(const std::string& name, const MachOArchi
} else {
simpleName = name;
}
// try LD_LIBRARY_PATH
std::string pathName;
pathName = getExistingPathname(simpleName, environmentVariables[LdLibraryPath], workingPath);
if (!pathName.empty())
return pathName;
std::string frameworkName = getFrameworkName(name);
if (!frameworkName.empty()) {
// strip the already contained suffix
@ -170,11 +170,11 @@ std::string DynamicLoader::getPathname(const std::string& name, const MachOArchi
if (!pathName.empty())
return pathName;
}
pathName = getExistingPathname(simpleName, environmentVariables[DyldLibraryPath], workingPath);
if (!pathName.empty())
return pathName;
// resolve placeholder
std::string resolvedName = replacePlaceholder(name, architecture);
if (!resolvedName.empty()) {
@ -182,11 +182,11 @@ std::string DynamicLoader::getPathname(const std::string& name, const MachOArchi
if (!pathName.empty())
return pathName;
}
if (name.find(PLACEHOLDERS[Rpath]) == 0) {
// substitute @rpath with all -rpath paths up the load chain
std::vector<std::string*> rpaths = architecture->getRpaths();
for (std::vector<std::string*>::iterator it = rpaths.begin(); it != rpaths.end(); ++it) {
// rpath may contain @loader_path or @executable_path
std::string rpath = replacePlaceholder((**it), architecture);
@ -196,7 +196,7 @@ std::string DynamicLoader::getPathname(const std::string& name, const MachOArchi
if (!pathName.empty())
return pathName;
}
// after checking against all stored rpaths substitute @rpath with LD_LIBRARY_PATH (if it is set)
EnvironmentPathVariable ldLibraryPaths = environmentVariables[LdLibraryPath];
if (!ldLibraryPaths.isEmpty()) {
@ -209,19 +209,19 @@ std::string DynamicLoader::getPathname(const std::string& name, const MachOArchi
}
}
}
// check pure path (either absolute or relative to working directory)
pathName = getExistingPathname(name, workingPath);
if (!pathName.empty())
return pathName;
// try fallbacks (or its defaults)
if (!frameworkName.empty()) {
pathName = getExistingPathname(frameworkName, environmentVariables[DyldFallbackFrameworkPath], workingPath);
if (!pathName.empty())
return pathName;
}
return getExistingPathname(name, environmentVariables[DyldFallbackLibraryPath], workingPath);
}
@ -231,28 +231,28 @@ std::string DynamicLoader::getFrameworkName(const std::string& name, const bool
if (name.find(".framework/") == std::string::npos) {
return "";
}
/* first look for the form Foo.framework/Foo
next look for the form Foo.framework/Versions/A/Foo
A and Foo are arbitrary strings without a slash */
// get Foo (part after last slash)
size_t lastSlashPosition = name.rfind(PATH_SEPARATOR);
if (lastSlashPosition == std::string::npos || lastSlashPosition == name.length() -1) {
return "";
}
const std::string foo = name.substr(lastSlashPosition+1);
const std::string frameworkPart = foo+".framework/";
const std::string framework = frameworkPart + foo;
if (endsWith(name, framework)) {
// strip first part
return framework;
}
int startPosition = name.find(frameworkPart+"Versions/");
bool hasCorrectEnd = endsWith(name, foo);
// TODO: check between Versions/ and foo there must be no additional slash
if (startPosition != std::string::npos) {
if (hasCorrectEnd) {
@ -268,7 +268,7 @@ std::string DynamicLoader::getFrameworkName(const std::string& name, const bool
}
}
}
// if we are at this part the given name was no framework
return "";
}
@ -297,11 +297,11 @@ std::string DynamicLoader::getExistingPathname(const std::string& file, const st
}
std::string DynamicLoader::getExistingPathname(const std::string& name, const std::string& workingPath, bool withSuffix) const {
// complete path
std::string usedName = name;
bool tryAgainWithoutSuffix = false;
// first try with suffix
if (withSuffix && !environmentVariables[DyldImageSuffix].isEmpty()) {
// only one suffix is considered

View File

@ -3,32 +3,32 @@
// use reference counting to reuse files for all used architectures
InternalFile* InternalFile::create(InternalFile* file) {
file->counter++;
return file;
file->counter++;
return file;
}
InternalFile* InternalFile::create(const std::string& filename) {
return new InternalFile(filename);
return new InternalFile(filename);
}
void InternalFile::release() {
counter--;
if (counter < 1) {
delete this;
}
counter--;
if (counter < 1) {
delete this;
}
}
InternalFile::InternalFile(const std::string& filename) :
filename(filename), counter(1)
filename(filename), counter(1)
{
// open file handle
file.open(this->filename, std::ios_base::in | std::ios_base::binary);
if (file.fail()) {
std::ostringstream error;
error << "Couldn't open file '" << filename << "'.";
throw MachOException(error.str());
}
// open file handle
file.open(this->filename, std::ios_base::in | std::ios_base::binary);
if (file.fail()) {
std::ostringstream error;
error << "Couldn't open file '" << filename << "'.";
throw MachOException(error.str());
}
struct stat buffer;
if (stat(filename.c_str(), &buffer) >= 0) {
_fileSize = buffer.st_size;
@ -38,12 +38,7 @@ InternalFile::InternalFile(const std::string& filename) :
// destructor is private since we use reference counting mechanism
InternalFile::~InternalFile() {
file.close();
}
std::string InternalFile::getPath() const {
return filename;
file.close();
}
/* returns whole filename (including path)*/
@ -58,7 +53,7 @@ std::string InternalFile::getName() const {
/* returns filename without path */
std::string InternalFile::getTitle() const {
return filename;
return filename;
}
unsigned long long InternalFile::getSize() const {
@ -66,27 +61,27 @@ unsigned long long InternalFile::getSize() const {
}
bool InternalFile::seek(long long int position) {
file.seekg(position, std::ios_base::beg);
if (file.fail()) {
file.clear();
return false;
}
return true;
file.seekg(position, std::ios_base::beg);
if (file.fail()) {
file.clear();
return false;
}
return true;
}
std::streamsize InternalFile::read(char* buffer, std::streamsize size) {
file.read(buffer, size);
if (file.fail()) {
file.clear();
return file.gcount();
}
// TODO: handle badbit
return size;
file.read(buffer, size);
if (file.fail()) {
file.clear();
return file.gcount();
}
// TODO: handle badbit
return size;
}
long long int InternalFile::getPosition() {
return file.tellg();
}
return file.tellg();
}
time_t InternalFile::getLastModificationTime() const {
return _lastWriteTime;

View File

@ -13,7 +13,7 @@ public:
static InternalFile* create(const std::string& filename);
void release();
std::string getPath() const;
std::string getFolder() const;
std::string getName() const;
std::string getTitle() const;
unsigned long long getSize() const;

View File

@ -204,10 +204,6 @@ std::string MachO::extractStringFromCFStringRef(CFStringRef cfStringRef) {
return string;
}
std::string MachO::getPath() const {
return file->getPath();
}
std::string MachO::getFileName() const {
std::string filename = file->getName();
return filename;

View File

@ -27,9 +27,7 @@ public:
time_t getLastModificationTime() const;
std::string getVersion() const;
std::string getName() const;
//sQIcon getIcon() const;*/
const MachO* getParent() { return parent;}
std::string getPath() const;
static DynamicLoader* dynamicLoader;
static int referenceCounter;
private:

View File

@ -3,100 +3,102 @@
#include "internalfile.h"
MachOFile::MachOFile(const std::string& filename,const MachOFile* parent, bool reversedByteOrder) :
file(InternalFile::create(filename)), position(0), reversedByteOrder(reversedByteOrder), parent(parent)
file(InternalFile::create(filename)), position(0), reversedByteOrder(reversedByteOrder), parent(parent)
{
if (parent) {
executablePath = parent->executablePath;
} else {
executablePath = getPath();
}
if (parent) {
executablePath = parent->executablePath;
} else {
executablePath = getDirectory();
}
}
MachOFile::MachOFile(const MachOFile& file, bool reversedByteOrder) :
file(InternalFile::create(file.file)), position(file.position), reversedByteOrder(reversedByteOrder), parent(file.parent), executablePath(file.executablePath)
file(InternalFile::create(file.file)), position(file.position), reversedByteOrder(reversedByteOrder), parent(file.parent), executablePath(file.executablePath)
{
}
MachOFile::~MachOFile() {
file->release();
file->release();
}
std::string MachOFile::getPath() const {
return file->getPath();
std::string MachOFile::getName() const {
std::string filename = file->getName();
return filename;
}
std::string MachOFile::getName() const {
std::string filename = file->getName();
return filename;
std::string MachOFile::getDirectory() const {
size_t found = file->getName().find_last_of("/");
return(file->getName().substr(0, found));
}
std::string MachOFile::getTitle() const { return file->getTitle(); }
unsigned long long MachOFile::getSize() const { return file->getSize(); }
time_t MachOFile::getLastModificationTime() const { return file->getLastModificationTime(); }
uint32_t MachOFile::readUint32() {
unsigned int temp;
readBytes((char*)&temp, sizeof(temp));
return getUint32(temp);
unsigned int temp;
readBytes((char*)&temp, sizeof(temp));
return getUint32(temp);
}
uint32_t MachOFile::readUint32LE() {
unsigned int temp;
readBytes((char*)&temp, sizeof(temp));
return getUint32LE(temp);
unsigned int temp;
readBytes((char*)&temp, sizeof(temp));
return getUint32LE(temp);
}
uint32_t MachOFile::readUint32BE() {
unsigned int temp;
readBytes((char*)&temp, sizeof(temp));
return getUint32BE(temp);
unsigned int temp;
readBytes((char*)&temp, sizeof(temp));
return getUint32BE(temp);
}
uint32_t MachOFile::getUint32BE(uint32_t data) {
return convertByteOrder((char*)&data, true, sizeof(data));
return convertByteOrder((char*)&data, true, sizeof(data));
}
uint32_t MachOFile::getUint32LE(uint32_t data) {
return convertByteOrder((char*)&data, false, sizeof(data));
return convertByteOrder((char*)&data, false, sizeof(data));
}
void MachOFile::readBytes(char* result, size_t size) {
if (file->getPosition() != position) {
file->seek(position);
}
if (file->read(result, size) != size)
throw MachOException("File '" + file->getName() + "' not big enough. Probably no valid Mach-O!");
position += size;
if (file->getPosition() != position) {
file->seek(position);
}
if (file->read(result, size) != size)
throw MachOException("File '" + file->getName() + "' not big enough. Probably no valid Mach-O!");
position += size;
}
// convert from big endian or little endian to native format (Intel=little endian) and return as unsigned int (32bit)
unsigned int MachOFile::convertByteOrder(char* data, bool isBigEndian, unsigned int numberOfBytes) {
assert(numberOfBytes> 0);
assert(numberOfBytes <= 4); // max 4 byte
unsigned int result = 0;
// big endian extract (most significant byte first) (will work on little and big-endian computers)
unsigned int numberOfShifts = isBigEndian ? numberOfBytes - 1 : 0;
for (unsigned int n = 0; n < numberOfBytes; n++) {
result |= static_cast<unsigned char>(data[n]) << (8 * numberOfShifts); // the bit shift will do the correct byte order for you
numberOfShifts += isBigEndian ? -1 : +1;
}
return result;
assert(numberOfBytes> 0);
assert(numberOfBytes <= 4); // max 4 byte
unsigned int result = 0;
// big endian extract (most significant byte first) (will work on little and big-endian computers)
unsigned int numberOfShifts = isBigEndian ? numberOfBytes - 1 : 0;
for (unsigned int n = 0; n < numberOfBytes; n++) {
result |= static_cast<unsigned char>(data[n]) << (8 * numberOfShifts); // the bit shift will do the correct byte order for you
numberOfShifts += isBigEndian ? -1 : +1;
}
return result;
}
uint32_t MachOFile::reverseByteOrder(uint32_t data) {
char* sourceData = (char*)&data;
uint32_t result;
char* destData = (char*)&result;
destData[3] = sourceData[0];
destData[2] = sourceData[1];
destData[1] = sourceData[2];
destData[0] = sourceData[3];
return result;
char* sourceData = (char*)&data;
uint32_t result;
char* destData = (char*)&result;
destData[3] = sourceData[0];
destData[2] = sourceData[1];
destData[1] = sourceData[2];
destData[0] = sourceData[3];
return result;
}

View File

@ -20,7 +20,7 @@ public:
uint32_t getUint32(unsigned int data) const {return (reversedByteOrder?reverseByteOrder(data):data);}
static uint32_t getUint32LE(uint32_t data);
static uint32_t getUint32BE(uint32_t data);
std::string getPath() const;
std::string getDirectory() const;
std::string getName() const;
std::string getTitle() const;
unsigned long long getSize() const;
@ -32,6 +32,7 @@ public:
private:
static unsigned int convertByteOrder(char* data, bool isBigEndian, unsigned int numberOfBytes);
static unsigned int reverseByteOrder(unsigned int data);
static std::string getDirectory(const std::string& path);
InternalFile* file;
long long int position;