Merge pull request #4914 from MarcZX100/codex/carry-link-follow-symlink-4026

fix(libkernel_sys): follow symbolic links in link
This commit is contained in:
Dean 2026-10-14 17:05:05 +13:00 committed by GitHub
commit f40b6930ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 17 additions and 3 deletions

View File

@ -363,13 +363,13 @@ int APS5_VABI link_nid_postfix(const char* existing, const char* created) {
if (const int error = ResolvePathError_nid_no_patch(existing, source)) return static_cast<int>(Fail(error));
if (const int error = ResolvePathError_nid_no_patch(created, destination)) return static_cast<int>(Fail(error));
std::error_code error;
const auto status = std::filesystem::symlink_status(source, error);
const auto status = std::filesystem::status(source, error);
if (!std::filesystem::exists(status)) return static_cast<int>(Fail(GuestEnoent));
if (std::filesystem::is_symlink(status)) throw std::runtime_error("link: a symbolic link as the existing path is not supported");
if (std::filesystem::is_directory(status)) return static_cast<int>(Fail(GuestEperm));
if (std::filesystem::exists(std::filesystem::symlink_status(destination, error))) return static_cast<int>(Fail(GuestEexist));
if (!std::filesystem::is_directory(destination.parent_path(), error)) return static_cast<int>(Fail(GuestEnoent));
std::filesystem::create_hard_link(source, destination, error);
const auto target = std::filesystem::is_symlink(source, error) ? std::filesystem::canonical(source, error) : source;
if (!error) std::filesystem::create_hard_link(target, destination, error);
if (error == std::errc::cross_device_link) return static_cast<int>(Fail(GuestExdev));
if (error) throw std::system_error(error, "link");
RecordWrittenPath_nid_no_patch(destination);

View File

@ -465,6 +465,20 @@ int main() {
Require(fchmodat_nid_postfix(base, longName.c_str(), 0600, 0) == -1 && Error() == 63);
#endif
Require(sceKernelClose(base) == 0);
#ifndef _WIN32
if (created == 0) {
const auto throughLink = (root / "through-link.bin").string();
Require(link_nid_postfix(symbolic.c_str(), throughLink.c_str()) == 0);
Require(!std::filesystem::is_symlink(std::filesystem::symlink_status(throughLink)));
Require(std::filesystem::equivalent(throughLink, original) && std::filesystem::hard_link_count(original) == 2);
Require(std::filesystem::remove(throughLink) && std::filesystem::hard_link_count(original) == 1);
Require(link_nid_postfix((root / "dangling").string().c_str(), throughLink.c_str()) == -1 && Error() == 2);
const auto directoryLink = (root / "directory-link").string();
Require(symlink_nid_postfix(".", directoryLink.c_str()) == 0);
Require(link_nid_postfix(directoryLink.c_str(), throughLink.c_str()) == -1 && Error() == 1);
Require(!std::filesystem::exists(std::filesystem::symlink_status(throughLink)));
}
#endif
std::filesystem::remove_all(root);
return 0;
}