| 71 | } |
| 72 | |
| 73 | std::string SymlinkResolver::realPath(Diagnostics& diags, const std::string& originalPath, |
| 74 | void (^callback)(const std::string& intermediateSymlink)) const { |
| 75 | // First make sure the path doesn't have any magic in it. |
| 76 | std::string path = originalPath; |
| 77 | normalizePath(path); |
| 78 | |
| 79 | std::set<std::string> seenSymlinks; |
| 80 | |
| 81 | // Now see if any prefix is a symlink |
| 82 | if (path.front() != '/') |
| 83 | return path; |
| 84 | |
| 85 | std::string::size_type prev_pos = 0; |
| 86 | while (prev_pos != std::string::npos) { |
| 87 | std::string::size_type pos = path.find("/", prev_pos + 1); |
| 88 | |
| 89 | // First look to see if this path component is special, eg, ., .., etc. |
| 90 | std::string component = path.substr(prev_pos, pos - prev_pos); |
| 91 | if (component == "/..") { |
| 92 | // Fold with the previous path component. |
| 93 | if (prev_pos == 0) { |
| 94 | // This is the root path, and .. applied to / is just / |
| 95 | path = path.substr(3); |
| 96 | prev_pos = 0; |
| 97 | } else { |
| 98 | std::string::size_type lastSlashPos = path.rfind("/", prev_pos - 1); |
| 99 | path = path.substr(0, lastSlashPos) + path.substr(pos); |
| 100 | prev_pos = lastSlashPos; |
| 101 | } |
| 102 | continue; |
| 103 | } else if (component == "/.") { |
| 104 | if (prev_pos == 0) { |
| 105 | // Path starts with /./ so just remove the first one. |
| 106 | path = path.substr(2); |
| 107 | } else { |
| 108 | if (pos == std::string::npos) { |
| 109 | // Trailing . on the path |
| 110 | path = path.substr(0, prev_pos ); |
| 111 | } else { |
| 112 | path = path.substr(0, prev_pos) + path.substr(pos); |
| 113 | } |
| 114 | } |
| 115 | continue; |
| 116 | } else if (component == "/") { |
| 117 | // Path must contain // somewhere so strip out the duplicates. |
| 118 | if (prev_pos == 0) { |
| 119 | // Path starts with // so just remove the first one. |
| 120 | path = path.substr(1); |
| 121 | } else { |
| 122 | if (pos == std::string::npos) { |
| 123 | // Trailing / on the path |
| 124 | path = path.substr(0, prev_pos); |
| 125 | prev_pos = pos; |
| 126 | } else { |
| 127 | path = path.substr(0, pos) + path.substr(pos + 1); |
| 128 | } |
| 129 | } |
| 130 | continue; |
no test coverage detected