mirror of
https://github.com/QuasarApp/macdependency.git
synced 2025-04-27 21:04:31 +00:00
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:
parent
66202abd66
commit
2004b7a99c
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user