diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Arm64/SyscallsEnum.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/Arm64/SyscallsEnum.h index 512d451c40..1169155b08 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Arm64/SyscallsEnum.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Arm64/SyscallsEnum.h @@ -348,6 +348,10 @@ enum Syscalls_Arm64 { SYSCALL_Arm64_lsm_set_self_attr = 460, SYSCALL_Arm64_lsm_list_modules = 461, SYSCALL_Arm64_mseal = 462, + SYSCALL_Arm64_setxattrat = 463, + SYSCALL_Arm64_getxattrat = 464, + SYSCALL_Arm64_listxattrat = 465, + SYSCALL_Arm64_removexattrat = 466, SYSCALL_Arm64_MAX = 512, // Unsupported syscalls on this host diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp index f2af354fbc..240cf46077 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.cpp @@ -1171,6 +1171,86 @@ uint64_t FileManager::LRemovexattr(const char* path, const char* name) { return ::lremovexattr(SelfPath, name); } +uint64_t FileManager::SetxattrAt(int dfd, const char* pathname, uint32_t at_flags, const char* name, const xattr_args* uargs, size_t usize) { + if (IsSelfNoFollow(pathname, at_flags)) { + // See Statx + return syscall(SYSCALL_DEF(setxattrat), dfd, pathname, at_flags, name, uargs, usize); + } + + auto NewPath = GetSelf(pathname); + const char* SelfPath = NewPath ? NewPath->data() : nullptr; + + FDPathTmpData TmpFilename; + auto Path = GetEmulatedFDPath(dfd, SelfPath, (at_flags & AT_SYMLINK_NOFOLLOW) == 0, TmpFilename); + if (Path.first != -1) { + uint64_t Result = syscall(SYSCALL_DEF(setxattrat), Path.first, Path.second, at_flags, name, uargs, usize); + if (Result != -1) { + return Result; + } + } + return syscall(SYSCALL_DEF(setxattrat), dfd, SelfPath, at_flags, name, uargs, usize); +} + +uint64_t FileManager::GetxattrAt(int dfd, const char* pathname, uint32_t at_flags, const char* name, const xattr_args* uargs, size_t usize) { + if (IsSelfNoFollow(pathname, at_flags)) { + // See Statx + return syscall(SYSCALL_DEF(getxattrat), dfd, pathname, at_flags, name, uargs, usize); + } + + auto NewPath = GetSelf(pathname); + const char* SelfPath = NewPath ? NewPath->data() : nullptr; + + FDPathTmpData TmpFilename; + auto Path = GetEmulatedFDPath(dfd, SelfPath, (at_flags & AT_SYMLINK_NOFOLLOW) == 0, TmpFilename); + if (Path.first != -1) { + uint64_t Result = syscall(SYSCALL_DEF(getxattrat), Path.first, Path.second, at_flags, name, uargs, usize); + if (Result != -1) { + return Result; + } + } + return syscall(SYSCALL_DEF(getxattrat), dfd, SelfPath, at_flags, name, uargs, usize); +} + +uint64_t FileManager::ListxattrAt(int dfd, const char* pathname, uint32_t at_flags, char* list, size_t size) { + if (IsSelfNoFollow(pathname, at_flags)) { + // See Statx + return syscall(SYSCALL_DEF(listxattrat), dfd, pathname, at_flags, list, size); + } + + auto NewPath = GetSelf(pathname); + const char* SelfPath = NewPath ? NewPath->data() : nullptr; + + FDPathTmpData TmpFilename; + auto Path = GetEmulatedFDPath(dfd, SelfPath, (at_flags & AT_SYMLINK_NOFOLLOW) == 0, TmpFilename); + if (Path.first != -1) { + uint64_t Result = syscall(SYSCALL_DEF(listxattrat), Path.first, Path.second, at_flags, list, size); + if (Result != -1) { + return Result; + } + } + return syscall(SYSCALL_DEF(listxattrat), dfd, SelfPath, at_flags, list, size); +} + +uint64_t FileManager::RemovexattrAt(int dfd, const char* pathname, uint32_t at_flags, const char* name) { + if (IsSelfNoFollow(pathname, at_flags)) { + // See Statx + return syscall(SYSCALL_DEF(removexattrat), dfd, pathname, at_flags, name); + } + + auto NewPath = GetSelf(pathname); + const char* SelfPath = NewPath ? NewPath->data() : nullptr; + + FDPathTmpData TmpFilename; + auto Path = GetEmulatedFDPath(dfd, SelfPath, (at_flags & AT_SYMLINK_NOFOLLOW) == 0, TmpFilename); + if (Path.first != -1) { + uint64_t Result = syscall(SYSCALL_DEF(removexattrat), Path.first, Path.second, at_flags, name); + if (Result != -1) { + return Result; + } + } + return syscall(SYSCALL_DEF(removexattrat), dfd, SelfPath, at_flags, name); +} + void FileManager::UpdatePID(uint32_t PID) { CurrentPID = PID; diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h index 77d50d44e3..a8a4278c1c 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/FileManagement.h @@ -75,6 +75,17 @@ class FileManager final { uint64_t LListxattr(const char* path, char* list, size_t size); uint64_t Removexattr(const char* path, const char* name); uint64_t LRemovexattr(const char* path, const char* name); + struct xattr_args { + uint64_t value; + uint32_t size; + uint32_t flags; + }; + + uint64_t SetxattrAt(int dfd, const char* pathname, uint32_t at_flags, const char* name, const xattr_args* uargs, size_t usize); + uint64_t GetxattrAt(int dfd, const char* pathname, uint32_t at_flags, const char* name, const xattr_args* uargs, size_t usize); + uint64_t ListxattrAt(int dfd, const char* pathname, uint32_t at_flags, char* list, size_t size); + uint64_t RemovexattrAt(int dfd, const char* pathname, uint32_t at_flags, const char* name); + // vfs uint64_t Statfs(const char* path, void* buf); diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FS.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FS.cpp index cbbb78d2d7..83e3a6994d 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FS.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/FS.cpp @@ -126,5 +126,31 @@ void RegisterFS(FEX::HLE::SyscallHandler* Handler) { uint64_t Result = FEX::HLE::_SyscallHandler->FM.LRemovexattr(path, name); SYSCALL_ERRNO(); }); + if (Handler->IsHostKernelVersionAtLeast(6, 13, 0)) { + REGISTER_SYSCALL_IMPL( + setxattrat, [](int dfd, const char* pathname, uint32_t at_flags, const char* name, const FileManager::xattr_args* uargs, size_t usize) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.SetxattrAt(dfd, pathname, at_flags, name, uargs, usize); + SYSCALL_ERRNO(); + }); + REGISTER_SYSCALL_IMPL( + getxattrat, [](int dfd, const char* pathname, uint32_t at_flags, const char* name, const FileManager::xattr_args* uargs, size_t usize) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.GetxattrAt(dfd, pathname, at_flags, name, uargs, usize); + SYSCALL_ERRNO(); + }); + + REGISTER_SYSCALL_IMPL(listxattrat, [](int dfd, const char* pathname, uint32_t at_flags, char* list, size_t size) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.ListxattrAt(dfd, pathname, at_flags, list, size); + SYSCALL_ERRNO(); + }); + REGISTER_SYSCALL_IMPL(removexattrat, [](int dfd, const char* pathname, uint32_t at_flags, const char* name) -> uint64_t { + uint64_t Result = FEX::HLE::_SyscallHandler->FM.RemovexattrAt(dfd, pathname, at_flags, name); + SYSCALL_ERRNO(); + }); + } else { + REGISTER_SYSCALL_IMPL(setxattrat, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(getxattrat, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(listxattrat, UnimplementedSyscallSafe); + REGISTER_SYSCALL_IMPL(removexattrat, UnimplementedSyscallSafe); + } } } // namespace FEX::HLE diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/SyscallsEnum.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/SyscallsEnum.h index 6397535ad2..1f709d137f 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/SyscallsEnum.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/SyscallsEnum.h @@ -480,6 +480,10 @@ enum Syscalls_x86 { SYSCALL_x86_lsm_set_self_attr = 460, SYSCALL_x86_lsm_list_modules = 461, SYSCALL_x86_mseal = 462, + SYSCALL_x86_setxattrat = 463, + SYSCALL_x86_getxattrat = 464, + SYSCALL_x86_listxattrat = 465, + SYSCALL_x86_removexattrat = 466, SYSCALL_x86_MAX = 512, }; } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/SyscallsEnum.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/SyscallsEnum.h index b0effda349..0ca8a99aaa 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/SyscallsEnum.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/SyscallsEnum.h @@ -400,6 +400,10 @@ enum Syscalls_x64 { SYSCALL_x64_lsm_set_self_attr = 460, SYSCALL_x64_lsm_list_modules = 461, SYSCALL_x64_mseal = 462, + SYSCALL_x64_setxattrat = 463, + SYSCALL_x64_getxattrat = 464, + SYSCALL_x64_listxattrat = 465, + SYSCALL_x64_removexattrat = 466, SYSCALL_x64_MAX = 512, // Unsupported syscalls on this host