Loading...
--- dyld/dyld-551.3/dyld3/shared-cache/FileUtils.cpp
+++ dyld/dyld-655.1/dyld3/shared-cache/FileUtils.cpp
@@ -45,6 +45,7 @@
#include <sstream>
#include "FileUtils.h"
+#include "StringUtils.h"
#include "Diagnostics.h"
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101200
@@ -52,7 +53,7 @@
#endif
-void iterateDirectoryTree(const std::string& pathPrefix, const std::string& path, bool (^dirFilter)(const std::string& path), void (^fileCallback)(const std::string& path, const struct stat&), bool processFiles)
+void iterateDirectoryTree(const std::string& pathPrefix, const std::string& path, bool (^dirFilter)(const std::string& path), void (^fileCallback)(const std::string& path, const struct stat&), bool processFiles, bool recurse)
{
std::string fullDirPath = pathPrefix + path;
DIR* dir = ::opendir(fullDirPath.c_str());
@@ -81,7 +82,8 @@
break;
if ( dirFilter(dirAndFile) )
break;
- iterateDirectoryTree(pathPrefix, dirAndFile, dirFilter, fileCallback);
+ if (recurse)
+ iterateDirectoryTree(pathPrefix, dirAndFile, dirFilter, fileCallback, processFiles, true);
break;
case DT_LNK:
// don't follow symlinks, dylib will be found through absolute path
@@ -101,7 +103,7 @@
int fd = mkstemp(pathTemplateSpace);
if ( fd != -1 ) {
ssize_t writtenSize = pwrite(fd, buffer, bufferLen, 0);
- if ( writtenSize == bufferLen ) {
+ if ( (size_t)writtenSize == bufferLen ) {
::fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); // mkstemp() makes file "rw-------", switch it to "rw-r--r--"
if ( ::rename(pathTemplateSpace, path.c_str()) == 0) {
::close(fd);
@@ -114,13 +116,13 @@
return false; // failure
}
-const void* mapFileReadOnly(const std::string& path, size_t& mappedSize)
+const void* mapFileReadOnly(const char* path, size_t& mappedSize)
{
struct stat statBuf;
- if ( ::stat(path.c_str(), &statBuf) != 0 )
+ if ( ::stat(path, &statBuf) != 0 )
return nullptr;
- int fd = ::open(path.c_str(), O_RDONLY);
+ int fd = ::open(path, O_RDONLY);
if ( fd < 0 )
return nullptr;
@@ -181,24 +183,37 @@
//
// The syntax is one dylib (install name) per line. Blank lines are ignored.
// Comments start with the # character.
-std::unordered_map<std::string, uint32_t> loadOrderFile(const std::string& orderFile) {
+std::unordered_map<std::string, uint32_t> parseOrderFile(const std::string& orderFileData) {
std::unordered_map<std::string, uint32_t> order;
- std::ifstream myfile(orderFile);
- if ( myfile.is_open() ) {
- uint32_t count = 0;
- std::string line;
- while ( std::getline(myfile, line) ) {
- size_t pos = line.find('#');
- if ( pos != std::string::npos )
- line.resize(pos);
- while ( !line.empty() && isspace(line.back()) ) {
- line.pop_back();
- }
- if ( !line.empty() )
- order[line] = count++;
- }
- myfile.close();
+ if (orderFileData.empty())
+ return order;
+
+ std::stringstream myData(orderFileData);
+
+ uint32_t count = 0;
+ std::string line;
+ while ( std::getline(myData, line) ) {
+ size_t pos = line.find('#');
+ if ( pos != std::string::npos )
+ line.resize(pos);
+ while ( !line.empty() && isspace(line.back()) ) {
+ line.pop_back();
+ }
+ if ( !line.empty() )
+ order[line] = count++;
+ }
+ return order;
+}
+
+std::string loadOrderFile(const std::string& orderFilePath) {
+ std::string order;
+
+ size_t size = 0;
+ char* data = (char*)mapFileReadOnly(orderFilePath.c_str(), size);
+ if (data) {
+ order = std::string(data, size);
+ ::munmap((void*)data, size);
}
return order;
@@ -303,23 +318,6 @@
FileCache::FileCache(void)
{
cache_queue = dispatch_queue_create("com.apple.dyld.cache.cache", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0));
-}
-
-void FileCache::preflightCache(Diagnostics& diags, const std::unordered_set<std::string>& paths)
-{
- for (auto& path : paths) {
- preflightCache(diags, path);
- }
-}
-
-void FileCache::preflightCache(Diagnostics& diags, const std::string& path)
-{
- dispatch_async(cache_queue, ^{
- std::string normalizedPath = normalize_absolute_file_path(path);
- if (entries.count(normalizedPath) == 0) {
- entries[normalizedPath] = fill(diags, normalizedPath);
- }
- });
}
std::pair<uint8_t*, struct stat> FileCache::cacheLoad(Diagnostics& diags, const std::string path)
@@ -410,5 +408,173 @@
return std::make_pair((uint8_t*)buffer_ptr, stat_buf);
}
+static void normalizePath(std::string& path) {
+ // Remove a bunch of stuff we don't need, like trailing slashes.
+ while ( !path.empty() && (path.back() == '/'))
+ path.pop_back();
+}
+
+void SymlinkResolver::addFile(Diagnostics& diags, std::string path) {
+ if (path.front() != '/') {
+ diags.error("Path must start with '/'");
+ return;
+ }
+ if (symlinks.find(path) != symlinks.end()) {
+ diags.error("Cannot add regular file as it is already a symlink");
+ return;
+ }
+ filePaths.insert(path);
+}
+
+void SymlinkResolver::addSymlink(Diagnostics& diags, std::string fromPath, std::string toPath) {
+ normalizePath(fromPath);
+ normalizePath(toPath);
+ if (fromPath.front() != '/') {
+ diags.error("Path must start with '/'");
+ return;
+ }
+ if (filePaths.find(fromPath) != filePaths.end()) {
+ diags.error("Cannot add symlink from '%s' as it is already a regular path", fromPath.c_str());
+ return;
+ }
+ auto itAndInserted = symlinks.insert({ fromPath, toPath });
+ if (!itAndInserted.second) {
+ // The path is already a symlink. Make sure its a dupe.
+ if (toPath != itAndInserted.first->second) {
+ diags.error("Duplicate symlink for path '%s'", fromPath.c_str());
+ return;
+ }
+ }
+}
+
+std::string SymlinkResolver::realPath(Diagnostics& diags, const std::string& originalPath) const {
+ // First make sure the path doesn't have any magic in it.
+ std::string path = originalPath;
+ normalizePath(path);
+
+ std::set<std::string> seenSymlinks;
+
+ // Now see if any prefix is a symlink
+ if (path.front() != '/')
+ return path;
+
+ std::string::size_type prev_pos = 0;
+ while (prev_pos != std::string::npos) {
+ std::string::size_type pos = path.find("/", prev_pos + 1);
+
+ // First look to see if this path component is special, eg, ., .., etc.
+ std::string component = path.substr(prev_pos, pos - prev_pos);
+ if (component == "/..") {
+ // Fold with the previous path component.
+ if (prev_pos == 0) {
+ // This is the root path, and .. applied to / is just /
+ path = path.substr(3);
+ prev_pos = 0;
+ } else {
+ std::string::size_type lastSlashPos = path.rfind("/", prev_pos - 1);
+ path = path.substr(0, lastSlashPos) + path.substr(pos);
+ prev_pos = lastSlashPos;
+ }
+ continue;
+ } else if (component == "/.") {
+ if (prev_pos == 0) {
+ // Path starts with /./ so just remove the first one.
+ path = path.substr(2);
+ } else {
+ if (pos == std::string::npos) {
+ // Trailing . on the path
+ path = path.substr(0, prev_pos );
+ } else {
+ path = path.substr(0, prev_pos) + path.substr(pos);
+ }
+ }
+ continue;
+ } else if (component == "/") {
+ // Path must contain // somewhere so strip out the duplicates.
+ if (prev_pos == 0) {
+ // Path starts with // so just remove the first one.
+ path = path.substr(1);
+ } else {
+ if (pos == std::string::npos) {
+ // Trailing / on the path
+ path = path.substr(0, prev_pos);
+ prev_pos = pos;
+ } else {
+ path = path.substr(0, pos) + path.substr(pos + 1);
+ }
+ }
+ continue;
+ }
+
+ // Path is not special, so see if it is a symlink to something.
+ std::string prefix = path.substr(0, pos);
+ //printf("%s\n", prefix.c_str());
+ auto it = symlinks.find(prefix);
+ if (it == symlinks.end()) {
+ // This is not a symlink so move to the next prefix.
+ prev_pos = pos;
+ continue;
+ }
+
+ // If we've already done this prefix then error out.
+ if (seenSymlinks.count(prefix)) {
+ diags.error("Loop in symlink processing for '%s'", originalPath.c_str());
+ return std::string();
+ }
+
+ seenSymlinks.insert(prefix);
+
+ // This is a symlink, so resolve the new path.
+ std::string toPath = it->second;
+ if (toPath.front() == '/') {
+ // Symlink points to an absolute address so substitute the whole prefix for the new path
+ // If we didn't substitute the last component of the path then there is also a path suffix.
+ std::string pathSuffix = "";
+ if (pos != std::string::npos) {
+ std::string::size_type nextSlashPos = path.find("/", pos + 1);
+ if (nextSlashPos != std::string::npos)
+ pathSuffix = path.substr(nextSlashPos);
+ }
+ path = toPath + pathSuffix;
+ prev_pos = 0;
+ continue;
+ }
+
+ // Symlink points to a relative path so we need to do more processing to get the real path.
+
+ // First calculate which part of the previous prefix we'll keep. Eg, in /a/b/c where "b -> blah", we want to keep /a here.
+ std::string prevPrefix = path.substr(0, prev_pos);
+ //printf("prevPrefix %s\n", prevPrefix.c_str());
+
+ // If we didn't substitute the last component of the path then there is also a path suffix.
+ std::string pathSuffix = "";
+ if (prefix.size() != path.size())
+ pathSuffix = path.substr(pos);
+
+ // The new path is the remaining prefix, plus the symlink target, plus any remaining suffix from the original path.
+ path = prevPrefix + "/" + toPath + pathSuffix;
+ prev_pos = 0;
+ }
+ return path;
+}
+
+std::vector<DyldSharedCache::FileAlias> SymlinkResolver::getResolvedSymlinks(Diagnostics& diags) {
+ diags.assertNoError();
+ std::vector<DyldSharedCache::FileAlias> aliases;
+ for (auto& fromPathAndToPath : symlinks) {
+ std::string newPath = realPath(diags, fromPathAndToPath.first);
+ if (diags.hasError()) {
+ aliases.clear();
+ return aliases;
+ }
+
+ if (filePaths.count(newPath)) {
+ aliases.push_back({ newPath, fromPathAndToPath.first });
+ // printf("symlink ('%s' -> '%s') resolved to '%s'\n", fromPathAndToPath.first.c_str(), fromPathAndToPath.second.c_str(), newPath.c_str());
+ }
+ }
+ return aliases;
+}
+
#endif // BUILDING_CACHE_BUILDER