feat(libkernel_sys): implement symlink

This commit is contained in:
Hannah Lyons 2026-10-11 06:42:20 -04:00
parent 0f863c1022
commit 6bc537ce01
2 changed files with 45 additions and 0 deletions

View File

@ -22,6 +22,9 @@ constexpr int GuestEfault = 14;
constexpr int GuestEinval = 22;
constexpr int GuestEexist = 17;
constexpr int GuestExdev = 18;
#ifdef _WIN32
constexpr int WindowsPrivilegeNotHeld = 1314;
#endif
std::atomic<std::uint16_t> creationMask{022};
@ -103,4 +106,28 @@ int APS5_VABI fchdir_nid_postfix(int fd) {
return 0;
}
int APS5_VABI symlink_nid_postfix(const char* target, const char* created) {
if (target == nullptr || created == nullptr) return static_cast<int>(Fail(GuestEfault));
if (*target == '\0' || *created == '\0') return static_cast<int>(Fail(GuestEnoent));
if (*target == '/') {
NotImplemented_nid_no_patch("symlink: absolute targets");
return -1;
}
const auto native = ResolvePath_nid_no_patch(created);
std::error_code error;
if (std::filesystem::exists(std::filesystem::symlink_status(native, error))) return static_cast<int>(Fail(GuestEexist));
if (!std::filesystem::is_directory(native.parent_path(), error)) return static_cast<int>(Fail(GuestEnoent));
const std::filesystem::path contents(target);
if (std::filesystem::is_directory(native.parent_path() / contents, error))
std::filesystem::create_directory_symlink(contents, native, error);
else
std::filesystem::create_symlink(contents, native, error);
#ifdef _WIN32
if (error.category() == std::system_category() && error.value() == WindowsPrivilegeNotHeld) return static_cast<int>(Fail(GuestEperm));
#endif
if (error) throw std::system_error(error, "symlink");
RecordWrittenPath_nid_no_patch(native);
return 0;
}
}

View File

@ -23,6 +23,7 @@ int APS5_VABI sceKernelOpen(const char*, int, std::uint16_t);
int APS5_VABI sceKernelClose(int);
int APS5_VABI setsid_nid_postfix(void);
int APS5_VABI link_nid_postfix(const char*, const char*);
int APS5_VABI symlink_nid_postfix(const char*, const char*);
std::uint16_t APS5_VABI umask_nid_postfix(std::uint16_t);
int* APS5_VABI __error_nid_postfix();
}
@ -108,6 +109,23 @@ int main() {
Require(sceKernelClose(directory) == 0);
Require(fchdir_nid_postfix(directory) == -1 && Error() == 9);
Require(chdir_nid_postfix("/") == 0);
const auto symbolic = (root / "symbolic").string();
const int created = symlink_nid_postfix("original.bin", symbolic.c_str());
if (created == 0) {
Require(std::filesystem::is_symlink(std::filesystem::symlink_status(symbolic)));
Require(readlink_nid_postfix(symbolic.c_str(), buffer, sizeof(buffer)) == 12 && std::memcmp(buffer, "original.bin", 12) == 0);
Require(std::filesystem::file_size(symbolic) == std::filesystem::file_size(original));
Require(symlink_nid_postfix("original.bin", symbolic.c_str()) == -1 && Error() == 17);
const auto dangling = (root / "dangling").string();
Require(symlink_nid_postfix("missing.bin", dangling.c_str()) == 0);
Require(readlink_nid_postfix(dangling.c_str(), buffer, sizeof(buffer)) == 11 && !std::filesystem::exists(dangling));
} else {
Require(created == -1 && Error() == 1);
std::fprintf(stderr, "symbolic links unavailable: the symlink success cases not tested\n");
}
Require(symlink_nid_postfix("original.bin", (root / "missing" / "symbolic").string().c_str()) == -1 && Error() == 2);
Require(symlink_nid_postfix(nullptr, symbolic.c_str()) == -1 && Error() == 14);
Require(symlink_nid_postfix("original.bin", "") == -1 && Error() == 2);
std::filesystem::remove_all(root);
return 0;
}