feat(libkernel_sys): implement symlink
This commit is contained in:
parent
0f863c1022
commit
6bc537ce01
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue