[VFS] Reimplement ResolvePath. Add FindSymbolicLink, ResolveSymbolicLink.

This commit is contained in:
gibbed 2019-07-29 17:55:24 -05:00
parent 54b0e2aff6
commit 05d2d76cff
2 changed files with 45 additions and 48 deletions

View File

@ -66,15 +66,40 @@ bool VirtualFileSystem::UnregisterSymbolicLink(const std::string& path) {
return true; return true;
} }
bool VirtualFileSystem::IsSymbolicLink(const std::string& path) { bool VirtualFileSystem::FindSymbolicLink(const std::string& path,
auto global_lock = global_critical_region_.Acquire(); std::string& target) {
auto it = symlinks_.find(path); auto it =
if (it == symlinks_.end()) { std::find_if(symlinks_.cbegin(), symlinks_.cend(), [&](const auto& s) {
return xe::find_first_of_case(path, s.first) == 0;
});
if (it == symlinks_.cend()) {
return false; return false;
} }
target = (*it).second;
return true; return true;
} }
bool VirtualFileSystem::ResolveSymbolicLink(const std::string& path,
std::string& result) {
result = path;
bool was_resolved = false;
while (true) {
auto it =
std::find_if(symlinks_.cbegin(), symlinks_.cend(), [&](const auto& s) {
return xe::find_first_of_case(result, s.first) == 0;
});
if (it == symlinks_.cend()) {
break;
}
// Found symlink!
auto target_path = (*it).second;
auto relative_path = result.substr((*it).first.size());
result = target_path + relative_path;
was_resolved = true;
}
return was_resolved;
}
Entry* VirtualFileSystem::ResolvePath(const std::string& path) { Entry* VirtualFileSystem::ResolvePath(const std::string& path) {
auto global_lock = global_critical_region_.Acquire(); auto global_lock = global_critical_region_.Acquire();
@ -82,55 +107,25 @@ Entry* VirtualFileSystem::ResolvePath(const std::string& path) {
std::string normalized_path(xe::filesystem::CanonicalizePath(path)); std::string normalized_path(xe::filesystem::CanonicalizePath(path));
// Resolve symlinks. // Resolve symlinks.
std::string device_path; std::string resolved_path;
std::string relative_path; if (ResolveSymbolicLink(normalized_path, resolved_path)) {
for (int i = 0; i < 2; i++) { normalized_path = resolved_path;
for (const auto& it : symlinks_) {
if (xe::find_first_of_case(normalized_path, it.first) == 0) {
// Found symlink!
device_path = it.second;
if (relative_path.empty()) {
relative_path = normalized_path.substr(it.first.size());
} }
// Bit of a cheaty move here, but allows double symlinks to be resolved. // Find the device.
normalized_path = device_path; auto it =
break; std::find_if(devices_.cbegin(), devices_.cend(), [&](const auto& d) {
} return xe::find_first_of_case(normalized_path, d->mount_path()) == 0;
} });
if (it == devices_.cend()) {
// Break as soon as we've completely resolved the symlinks to a device. XELOGE("ResolvePath(%s) failed - device not found", path.c_str());
if (!IsSymbolicLink(device_path)) {
break;
}
}
if (device_path.empty()) {
// Symlink wasn't passed in - Check if we've received a raw device name.
for (auto& device : devices_) {
if (xe::find_first_of_case(normalized_path, device->mount_path()) == 0) {
device_path = device->mount_path();
relative_path = normalized_path.substr(device_path.size());
}
}
}
if (device_path.empty()) {
XELOGE("ResolvePath(%s) failed - no root found", path.c_str());
return nullptr; return nullptr;
} }
// Scan all devices. const auto& device = *it;
for (auto& device : devices_) { auto relative_path = normalized_path.substr(device->mount_path().size());
if (strcasecmp(device_path.c_str(), device->mount_path().c_str()) == 0) {
return device->ResolvePath(relative_path); return device->ResolvePath(relative_path);
} }
}
XELOGE("ResolvePath(%s) failed - device not found (%s)", path.c_str(),
device_path.c_str());
return nullptr;
}
Entry* VirtualFileSystem::ResolveBasePath(const std::string& path) { Entry* VirtualFileSystem::ResolveBasePath(const std::string& path) {
auto base_path = xe::find_base_path(path); auto base_path = xe::find_base_path(path);

View File

@ -33,7 +33,7 @@ class VirtualFileSystem {
bool RegisterSymbolicLink(const std::string& path, const std::string& target); bool RegisterSymbolicLink(const std::string& path, const std::string& target);
bool UnregisterSymbolicLink(const std::string& path); bool UnregisterSymbolicLink(const std::string& path);
bool IsSymbolicLink(const std::string& path); bool FindSymbolicLink(const std::string& path, std::string& target);
Entry* ResolvePath(const std::string& path); Entry* ResolvePath(const std::string& path);
Entry* ResolveBasePath(const std::string& path); Entry* ResolveBasePath(const std::string& path);
@ -50,6 +50,8 @@ class VirtualFileSystem {
xe::global_critical_region global_critical_region_; xe::global_critical_region global_critical_region_;
std::vector<std::unique_ptr<Device>> devices_; std::vector<std::unique_ptr<Device>> devices_;
std::unordered_map<std::string, std::string> symlinks_; std::unordered_map<std::string, std::string> symlinks_;
bool ResolveSymbolicLink(const std::string& path, std::string& result);
}; };
} // namespace vfs } // namespace vfs