[libc-commits] [libc] [libc] Add the get and set sys/xattr.h entrypoints. (PR #224729)
Alex Strelnikov via libc-commits
libc-commits at lists.llvm.org
Thu Sep 24 07:45:05 PDT 2026
https://github.com/strel-12 updated https://github.com/llvm/llvm-project/pull/224729
>From 8ee513607279a518bc14b5a5f5d2e06a3cbfb39b Mon Sep 17 00:00:00 2001
From: Alex Strelnikov <strel at google.com>
Date: Fri, 18 Sep 2026 19:54:59 +0000
Subject: [PATCH 1/6] Add the get and set sys/xattr.h entrypoints.
---
libc/config/linux/aarch64/entrypoints.txt | 6 +
libc/config/linux/x86_64/entrypoints.txt | 6 +
libc/hdr/CMakeLists.txt | 8 +
libc/hdr/sys_xattr_macros.h | 27 +++
libc/include/CMakeLists.txt | 1 +
libc/include/llvm-libc-macros/CMakeLists.txt | 6 +
.../llvm-libc-macros/linux/CMakeLists.txt | 6 +
.../llvm-libc-macros/linux/sys-xattr-macros.h | 20 ++
.../llvm-libc-macros/sys-xattr-macros.h | 21 ++
libc/include/sys/xattr.yaml | 63 +++++-
.../linux/syscall_wrappers/CMakeLists.txt | 72 +++++++
.../OSUtil/linux/syscall_wrappers/fgetxattr.h | 34 ++++
.../OSUtil/linux/syscall_wrappers/fsetxattr.h | 34 ++++
.../OSUtil/linux/syscall_wrappers/getxattr.h | 34 ++++
.../OSUtil/linux/syscall_wrappers/lgetxattr.h | 34 ++++
.../OSUtil/linux/syscall_wrappers/lsetxattr.h | 34 ++++
.../OSUtil/linux/syscall_wrappers/setxattr.h | 34 ++++
libc/src/sys/xattr/CMakeLists.txt | 42 ++++
libc/src/sys/xattr/fgetxattr.h | 27 +++
libc/src/sys/xattr/fsetxattr.h | 27 +++
libc/src/sys/xattr/getxattr.h | 27 +++
libc/src/sys/xattr/lgetxattr.h | 27 +++
libc/src/sys/xattr/linux/CMakeLists.txt | 90 ++++++++
libc/src/sys/xattr/linux/fgetxattr.cpp | 35 ++++
libc/src/sys/xattr/linux/fsetxattr.cpp | 38 ++++
libc/src/sys/xattr/linux/getxattr.cpp | 37 ++++
libc/src/sys/xattr/linux/lgetxattr.cpp | 37 ++++
libc/src/sys/xattr/linux/lsetxattr.cpp | 39 ++++
libc/src/sys/xattr/linux/setxattr.cpp | 39 ++++
libc/src/sys/xattr/lsetxattr.h | 27 +++
libc/src/sys/xattr/setxattr.h | 27 +++
libc/test/src/sys/xattr/CMakeLists.txt | 134 ++++++++++++
libc/test/src/sys/xattr/fgetxattr_test.cpp | 123 +++++++++++
libc/test/src/sys/xattr/fsetxattr_test.cpp | 158 ++++++++++++++
libc/test/src/sys/xattr/getxattr_test.cpp | 158 ++++++++++++++
libc/test/src/sys/xattr/lgetxattr_test.cpp | 148 ++++++++++++++
libc/test/src/sys/xattr/lsetxattr_test.cpp | 164 +++++++++++++++
libc/test/src/sys/xattr/setxattr_test.cpp | 192 ++++++++++++++++++
38 files changed, 2035 insertions(+), 1 deletion(-)
create mode 100644 libc/hdr/sys_xattr_macros.h
create mode 100644 libc/include/llvm-libc-macros/linux/sys-xattr-macros.h
create mode 100644 libc/include/llvm-libc-macros/sys-xattr-macros.h
create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/fgetxattr.h
create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/fsetxattr.h
create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/getxattr.h
create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/lgetxattr.h
create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/lsetxattr.h
create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/setxattr.h
create mode 100644 libc/src/sys/xattr/fgetxattr.h
create mode 100644 libc/src/sys/xattr/fsetxattr.h
create mode 100644 libc/src/sys/xattr/getxattr.h
create mode 100644 libc/src/sys/xattr/lgetxattr.h
create mode 100644 libc/src/sys/xattr/linux/fgetxattr.cpp
create mode 100644 libc/src/sys/xattr/linux/fsetxattr.cpp
create mode 100644 libc/src/sys/xattr/linux/getxattr.cpp
create mode 100644 libc/src/sys/xattr/linux/lgetxattr.cpp
create mode 100644 libc/src/sys/xattr/linux/lsetxattr.cpp
create mode 100644 libc/src/sys/xattr/linux/setxattr.cpp
create mode 100644 libc/src/sys/xattr/lsetxattr.h
create mode 100644 libc/src/sys/xattr/setxattr.h
create mode 100644 libc/test/src/sys/xattr/fgetxattr_test.cpp
create mode 100644 libc/test/src/sys/xattr/fsetxattr_test.cpp
create mode 100644 libc/test/src/sys/xattr/getxattr_test.cpp
create mode 100644 libc/test/src/sys/xattr/lgetxattr_test.cpp
create mode 100644 libc/test/src/sys/xattr/lsetxattr_test.cpp
create mode 100644 libc/test/src/sys/xattr/setxattr_test.cpp
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index fe1c2965f778b..20cff8a4b8f2d 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -385,6 +385,12 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.wait.waitpid
# sys/xattr.h entrypoints
+ libc.src.sys.xattr.fgetxattr
+ libc.src.sys.xattr.getxattr
+ libc.src.sys.xattr.lgetxattr
+ libc.src.sys.xattr.fsetxattr
+ libc.src.sys.xattr.setxattr
+ libc.src.sys.xattr.lsetxattr
libc.src.sys.xattr.flistxattr
libc.src.sys.xattr.listxattr
libc.src.sys.xattr.llistxattr
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index f21d48d6ef9e7..2e5b944eb2852 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -424,6 +424,12 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.wait.waitpid
# sys/xattr.h entrypoints
+ libc.src.sys.xattr.fgetxattr
+ libc.src.sys.xattr.getxattr
+ libc.src.sys.xattr.lgetxattr
+ libc.src.sys.xattr.fsetxattr
+ libc.src.sys.xattr.setxattr
+ libc.src.sys.xattr.lsetxattr
libc.src.sys.xattr.flistxattr
libc.src.sys.xattr.listxattr
libc.src.sys.xattr.llistxattr
diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index fa01bc55785da..58f1b55946514 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -274,6 +274,14 @@ add_proxy_header_library(
libc.include.llvm-libc-macros.sys_wait_macros
)
+add_proxy_header_library(
+ sys_xattr_macros
+ HDRS
+ sys_xattr_macros.h
+ FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-macros.sys_xattr_macros
+)
+
add_proxy_header_library(
termios_macros
HDRS
diff --git a/libc/hdr/sys_xattr_macros.h b/libc/hdr/sys_xattr_macros.h
new file mode 100644
index 0000000000000..b65fa7958511c
--- /dev/null
+++ b/libc/hdr/sys_xattr_macros.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Proxy header for macro values defined in sys/xattr.h.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_HDR_SYS_XATTR_MACROS_H
+#define LLVM_LIBC_HDR_SYS_XATTR_MACROS_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-macros/sys-xattr-macros.h"
+
+#else // Overlay mode
+
+#include <sys/xattr.h>
+
+#endif // LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_SYS_XATTR_MACROS_H
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index a45026de31ee5..805b97ed9017a 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -1103,6 +1103,7 @@ add_header_macro(
sys/xattr.h
DEPENDS
.llvm_libc_common_h
+ .llvm-libc-macros.sys_xattr_macros
.llvm-libc-types.size_t
.llvm-libc-types.ssize_t
)
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
index 9e9559056dae4..5600fcdca21a1 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -383,6 +383,12 @@ add_macro_header(
sys-wait-macros.h
)
+add_macro_header(
+ sys_xattr_macros
+ HDR
+ sys-xattr-macros.h
+)
+
add_macro_header(
sys_sysmacros_macros
HDR
diff --git a/libc/include/llvm-libc-macros/linux/CMakeLists.txt b/libc/include/llvm-libc-macros/linux/CMakeLists.txt
index 5a032252d9893..a634b0a9eb9e9 100644
--- a/libc/include/llvm-libc-macros/linux/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/linux/CMakeLists.txt
@@ -100,6 +100,12 @@ add_header(
sys-wait-macros.h
)
+add_header(
+ sys_xattr_macros
+ HDR
+ sys-xattr-macros.h
+)
+
add_header(
sys_sysmacros_macros
HDR
diff --git a/libc/include/llvm-libc-macros/linux/sys-xattr-macros.h b/libc/include/llvm-libc-macros/linux/sys-xattr-macros.h
new file mode 100644
index 0000000000000..37fcb5b47a2bb
--- /dev/null
+++ b/libc/include/llvm-libc-macros/linux/sys-xattr-macros.h
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Linux specific declarations of macros from sys/xattr.h.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_MACROS_LINUX_SYS_XATTR_MACROS_H
+#define LLVM_LIBC_MACROS_LINUX_SYS_XATTR_MACROS_H
+
+#define XATTR_CREATE 1
+#define XATTR_REPLACE 2
+
+#endif // LLVM_LIBC_MACROS_LINUX_SYS_XATTR_MACROS_H
diff --git a/libc/include/llvm-libc-macros/sys-xattr-macros.h b/libc/include/llvm-libc-macros/sys-xattr-macros.h
new file mode 100644
index 0000000000000..37eba86749621
--- /dev/null
+++ b/libc/include/llvm-libc-macros/sys-xattr-macros.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Macros defined in sys/xattr.h.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_MACROS_SYS_XATTR_MACROS_H
+#define LLVM_LIBC_MACROS_SYS_XATTR_MACROS_H
+
+#ifdef __linux__
+#include "linux/sys-xattr-macros.h"
+#endif
+
+#endif // LLVM_LIBC_MACROS_SYS_XATTR_MACROS_H
diff --git a/libc/include/sys/xattr.yaml b/libc/include/sys/xattr.yaml
index 5f8b6174af025..0f680630c34a6 100644
--- a/libc/include/sys/xattr.yaml
+++ b/libc/include/sys/xattr.yaml
@@ -1,13 +1,74 @@
header: sys/xattr.h
standards:
- linux
-macros: []
+macros:
+ - macro_name: XATTR_CREATE
+ macro_header: sys-xattr-macros.h
+ - macro_name: XATTR_REPLACE
+ macro_header: sys-xattr-macros.h
types:
- type_name: size_t
- type_name: ssize_t
enums: []
objects: []
functions:
+ - name: getxattr
+ standards:
+ - linux
+ return_type: ssize_t
+ arguments:
+ - type: const char *
+ - type: const char *
+ - type: void *
+ - type: size_t
+ - name: lgetxattr
+ standards:
+ - linux
+ return_type: ssize_t
+ arguments:
+ - type: const char *
+ - type: const char *
+ - type: void *
+ - type: size_t
+ - name: fgetxattr
+ standards:
+ - linux
+ return_type: ssize_t
+ arguments:
+ - type: int
+ - type: const char *
+ - type: void *
+ - type: size_t
+ - name: setxattr
+ standards:
+ - linux
+ return_type: int
+ arguments:
+ - type: const char *
+ - type: const char *
+ - type: const void *
+ - type: size_t
+ - type: int
+ - name: lsetxattr
+ standards:
+ - linux
+ return_type: int
+ arguments:
+ - type: const char *
+ - type: const char *
+ - type: const void *
+ - type: size_t
+ - type: int
+ - name: fsetxattr
+ standards:
+ - linux
+ return_type: int
+ arguments:
+ - type: const char *
+ - type: const char *
+ - type: const void *
+ - type: size_t
+ - type: int
- name: listxattr
standards:
- linux
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index f5f28f51f49f6..99d1792c85696 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -215,6 +215,78 @@ add_header_library(
libc.include.sys_syscall
)
+add_header_library(
+ fgetxattr
+ HDRS
+ fgetxattr.h
+ DEPENDS
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+ libc.include.sys_syscall
+)
+
+add_header_library(
+ getxattr
+ HDRS
+ getxattr.h
+ DEPENDS
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+ libc.include.sys_syscall
+)
+
+add_header_library(
+ lgetxattr
+ HDRS
+ lgetxattr.h
+ DEPENDS
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+ libc.include.sys_syscall
+)
+
+add_header_library(
+ fsetxattr
+ HDRS
+ fsetxattr.h
+ DEPENDS
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+ libc.include.sys_syscall
+)
+
+add_header_library(
+ setxattr
+ HDRS
+ setxattr.h
+ DEPENDS
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+ libc.include.sys_syscall
+)
+
+add_header_library(
+ lsetxattr
+ HDRS
+ lsetxattr.h
+ DEPENDS
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.macros.config
+ libc.include.sys_syscall
+)
+
add_header_library(
flistxattr
HDRS
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/fgetxattr.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/fgetxattr.h
new file mode 100644
index 0000000000000..e37b9c787f22b
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/fgetxattr.h
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Syscall wrapper for fgetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FGETXATTR_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FGETXATTR_H
+
+#include "src/__support/OSUtil/linux/syscall.h"
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h>
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<ssize_t> fgetxattr(int fd, const char *name, void *value,
+ size_t size) {
+ return syscall_checked<ssize_t>(SYS_fgetxattr, fd, name, value, size);
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FGETXATTR_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/fsetxattr.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/fsetxattr.h
new file mode 100644
index 0000000000000..cd818266d59a1
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/fsetxattr.h
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Syscall wrapper for fsetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FSETXATTR_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FSETXATTR_H
+
+#include "src/__support/OSUtil/linux/syscall.h"
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h>
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<int> fsetxattr(int fd, const char *name, const void *value,
+ size_t size, int flags) {
+ return syscall_checked<int>(SYS_fsetxattr, fd, name, value, size, flags);
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FSETXATTR_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/getxattr.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/getxattr.h
new file mode 100644
index 0000000000000..cfc532eadfb4a
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/getxattr.h
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Syscall wrapper for getxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETXATTR_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETXATTR_H
+
+#include "src/__support/OSUtil/linux/syscall.h"
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h>
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<ssize_t> getxattr(const char *path, const char *name,
+ void *value, size_t size) {
+ return syscall_checked<ssize_t>(SYS_getxattr, path, name, value, size);
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETXATTR_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/lgetxattr.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/lgetxattr.h
new file mode 100644
index 0000000000000..1975732642df4
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/lgetxattr.h
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Syscall wrapper for lgetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LGETXATTR_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LGETXATTR_H
+
+#include "src/__support/OSUtil/linux/syscall.h"
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h>
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<ssize_t> lgetxattr(const char *path, const char *name,
+ void *value, size_t size) {
+ return syscall_checked<ssize_t>(SYS_lgetxattr, path, name, value, size);
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LGETXATTR_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/lsetxattr.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/lsetxattr.h
new file mode 100644
index 0000000000000..2eb2663cbd3ec
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/lsetxattr.h
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Syscall wrapper for lsetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LSETXATTR_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LSETXATTR_H
+
+#include "src/__support/OSUtil/linux/syscall.h"
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h>
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<int> lsetxattr(const char *path, const char *name,
+ const void *value, size_t size, int flags) {
+ return syscall_checked<int>(SYS_lsetxattr, path, name, value, size, flags);
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LSETXATTR_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/setxattr.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/setxattr.h
new file mode 100644
index 0000000000000..c10a8455fd92b
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/setxattr.h
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Syscall wrapper for setxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETXATTR_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETXATTR_H
+
+#include "src/__support/OSUtil/linux/syscall.h"
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h>
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<int> setxattr(const char *path, const char *name,
+ const void *value, size_t size, int flags) {
+ return syscall_checked<int>(SYS_setxattr, path, name, value, size, flags);
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETXATTR_H
diff --git a/libc/src/sys/xattr/CMakeLists.txt b/libc/src/sys/xattr/CMakeLists.txt
index d008639bddf0d..b02fd40ea7de3 100644
--- a/libc/src/sys/xattr/CMakeLists.txt
+++ b/libc/src/sys/xattr/CMakeLists.txt
@@ -2,6 +2,48 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
endif()
+add_entrypoint_object(
+ fgetxattr
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.fgetxattr
+)
+
+add_entrypoint_object(
+ getxattr
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.getxattr
+)
+
+add_entrypoint_object(
+ lgetxattr
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.lgetxattr
+)
+
+add_entrypoint_object(
+ fsetxattr
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.fsetxattr
+)
+
+add_entrypoint_object(
+ setxattr
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.setxattr
+)
+
+add_entrypoint_object(
+ lsetxattr
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.lsetxattr
+)
+
add_entrypoint_object(
flistxattr
ALIAS
diff --git a/libc/src/sys/xattr/fgetxattr.h b/libc/src/sys/xattr/fgetxattr.h
new file mode 100644
index 0000000000000..68f24e1af28f0
--- /dev/null
+++ b/libc/src/sys/xattr/fgetxattr.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Function declaration of fgetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_FGETXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_FGETXATTR_H
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+ssize_t fgetxattr(int fd, const char *name, void *value, size_t size);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_FGETXATTR_H
diff --git a/libc/src/sys/xattr/fsetxattr.h b/libc/src/sys/xattr/fsetxattr.h
new file mode 100644
index 0000000000000..75eb85df31f13
--- /dev/null
+++ b/libc/src/sys/xattr/fsetxattr.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Function declaration of fsetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_FSETXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_FSETXATTR_H
+
+#include "hdr/types/size_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int fsetxattr(int fd, const char *name, const void *value, size_t size,
+ int flags);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_FSETXATTR_H
diff --git a/libc/src/sys/xattr/getxattr.h b/libc/src/sys/xattr/getxattr.h
new file mode 100644
index 0000000000000..45668baa4bea2
--- /dev/null
+++ b/libc/src/sys/xattr/getxattr.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Function declaration of getxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_GETXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_GETXATTR_H
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+ssize_t getxattr(const char *path, const char *name, void *value, size_t size);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_GETXATTR_H
diff --git a/libc/src/sys/xattr/lgetxattr.h b/libc/src/sys/xattr/lgetxattr.h
new file mode 100644
index 0000000000000..525dd5c7c1603
--- /dev/null
+++ b/libc/src/sys/xattr/lgetxattr.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Function declaration of lgetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_LGETXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_LGETXATTR_H
+
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_LGETXATTR_H
diff --git a/libc/src/sys/xattr/linux/CMakeLists.txt b/libc/src/sys/xattr/linux/CMakeLists.txt
index 0d80394c7f8f1..e9a48a8cc6581 100644
--- a/libc/src/sys/xattr/linux/CMakeLists.txt
+++ b/libc/src/sys/xattr/linux/CMakeLists.txt
@@ -1,3 +1,93 @@
+add_entrypoint_object(
+ fgetxattr
+ SRCS
+ fgetxattr.cpp
+ HDRS
+ ../fgetxattr.h
+ DEPENDS
+ libc.src.__support.OSUtil.linux.syscall_wrappers.fgetxattr
+ libc.src.__support.common
+ libc.src.__support.libc_errno
+ libc.src.__support.macros.config
+ libc.src.__support.macros.null_check
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ getxattr
+ SRCS
+ getxattr.cpp
+ HDRS
+ ../getxattr.h
+ DEPENDS
+ libc.src.__support.OSUtil.linux.syscall_wrappers.getxattr
+ libc.src.__support.common
+ libc.src.__support.libc_errno
+ libc.src.__support.macros.config
+ libc.src.__support.macros.null_check
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ lgetxattr
+ SRCS
+ lgetxattr.cpp
+ HDRS
+ ../lgetxattr.h
+ DEPENDS
+ libc.src.__support.OSUtil.linux.syscall_wrappers.lgetxattr
+ libc.src.__support.common
+ libc.src.__support.libc_errno
+ libc.src.__support.macros.config
+ libc.src.__support.macros.null_check
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ fsetxattr
+ SRCS
+ fsetxattr.cpp
+ HDRS
+ ../fsetxattr.h
+ DEPENDS
+ libc.src.__support.OSUtil.linux.syscall_wrappers.fsetxattr
+ libc.src.__support.common
+ libc.src.__support.libc_errno
+ libc.src.__support.macros.config
+ libc.src.__support.macros.null_check
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ setxattr
+ SRCS
+ setxattr.cpp
+ HDRS
+ ../setxattr.h
+ DEPENDS
+ libc.src.__support.OSUtil.linux.syscall_wrappers.setxattr
+ libc.src.__support.common
+ libc.src.__support.libc_errno
+ libc.src.__support.macros.config
+ libc.src.__support.macros.null_check
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ lsetxattr
+ SRCS
+ lsetxattr.cpp
+ HDRS
+ ../lsetxattr.h
+ DEPENDS
+ libc.src.__support.OSUtil.linux.syscall_wrappers.lsetxattr
+ libc.src.__support.common
+ libc.src.__support.libc_errno
+ libc.src.__support.macros.config
+ libc.src.__support.macros.null_check
+ libc.src.errno.errno
+)
+
add_entrypoint_object(
flistxattr
SRCS
diff --git a/libc/src/sys/xattr/linux/fgetxattr.cpp b/libc/src/sys/xattr/linux/fgetxattr.cpp
new file mode 100644
index 0000000000000..b7ee5c9fe2e78
--- /dev/null
+++ b/libc/src/sys/xattr/linux/fgetxattr.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of fgetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/xattr/fgetxattr.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/fgetxattr.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(ssize_t, fgetxattr,
+ (int fd, const char *name, void *value, size_t size)) {
+ LIBC_CRASH_ON_NULLPTR(name);
+
+ ErrorOr<ssize_t> ret = linux_syscalls::fgetxattr(fd, name, value, size);
+ if (!ret) {
+ libc_errno = ret.error();
+ return -1;
+ }
+ return *ret;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/xattr/linux/fsetxattr.cpp b/libc/src/sys/xattr/linux/fsetxattr.cpp
new file mode 100644
index 0000000000000..d63fb51201878
--- /dev/null
+++ b/libc/src/sys/xattr/linux/fsetxattr.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of fsetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/xattr/fsetxattr.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/fsetxattr.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, fsetxattr,
+ (int fd, const char *name, const void *value, size_t size,
+ int flags)) {
+ LIBC_CRASH_ON_NULLPTR(name);
+ if (size != 0)
+ LIBC_CRASH_ON_NULLPTR(value);
+
+ ErrorOr<int> ret = linux_syscalls::fsetxattr(fd, name, value, size, flags);
+ if (!ret) {
+ libc_errno = ret.error();
+ return -1;
+ }
+ return *ret;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/xattr/linux/getxattr.cpp b/libc/src/sys/xattr/linux/getxattr.cpp
new file mode 100644
index 0000000000000..d4f9361b8613b
--- /dev/null
+++ b/libc/src/sys/xattr/linux/getxattr.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of getxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/xattr/getxattr.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/getxattr.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(ssize_t, getxattr,
+ (const char *path, const char *name, void *value,
+ size_t size)) {
+ LIBC_CRASH_ON_NULLPTR(path);
+ LIBC_CRASH_ON_NULLPTR(name);
+
+ ErrorOr<ssize_t> ret = linux_syscalls::getxattr(path, name, value, size);
+ if (!ret) {
+ libc_errno = ret.error();
+ return -1;
+ }
+ return *ret;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/xattr/linux/lgetxattr.cpp b/libc/src/sys/xattr/linux/lgetxattr.cpp
new file mode 100644
index 0000000000000..0e9885f1e5cad
--- /dev/null
+++ b/libc/src/sys/xattr/linux/lgetxattr.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of lgetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/xattr/lgetxattr.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/lgetxattr.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(ssize_t, lgetxattr,
+ (const char *path, const char *name, void *value,
+ size_t size)) {
+ LIBC_CRASH_ON_NULLPTR(path);
+ LIBC_CRASH_ON_NULLPTR(name);
+
+ ErrorOr<ssize_t> ret = linux_syscalls::lgetxattr(path, name, value, size);
+ if (!ret) {
+ libc_errno = ret.error();
+ return -1;
+ }
+ return *ret;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/xattr/linux/lsetxattr.cpp b/libc/src/sys/xattr/linux/lsetxattr.cpp
new file mode 100644
index 0000000000000..aea81c5842387
--- /dev/null
+++ b/libc/src/sys/xattr/linux/lsetxattr.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of lsetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/xattr/lsetxattr.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/lsetxattr.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, lsetxattr,
+ (const char *path, const char *name, const void *value,
+ size_t size, int flags)) {
+ LIBC_CRASH_ON_NULLPTR(path);
+ LIBC_CRASH_ON_NULLPTR(name);
+ if (size != 0)
+ LIBC_CRASH_ON_NULLPTR(value);
+
+ ErrorOr<int> ret = linux_syscalls::lsetxattr(path, name, value, size, flags);
+ if (!ret) {
+ libc_errno = ret.error();
+ return -1;
+ }
+ return *ret;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/xattr/linux/setxattr.cpp b/libc/src/sys/xattr/linux/setxattr.cpp
new file mode 100644
index 0000000000000..f0158645329f5
--- /dev/null
+++ b/libc/src/sys/xattr/linux/setxattr.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of setxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/xattr/setxattr.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/setxattr.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, setxattr,
+ (const char *path, const char *name, const void *value,
+ size_t size, int flags)) {
+ LIBC_CRASH_ON_NULLPTR(path);
+ LIBC_CRASH_ON_NULLPTR(name);
+ if (size != 0)
+ LIBC_CRASH_ON_NULLPTR(value);
+
+ ErrorOr<int> ret = linux_syscalls::setxattr(path, name, value, size, flags);
+ if (!ret) {
+ libc_errno = ret.error();
+ return -1;
+ }
+ return *ret;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sys/xattr/lsetxattr.h b/libc/src/sys/xattr/lsetxattr.h
new file mode 100644
index 0000000000000..6e6170bc896de
--- /dev/null
+++ b/libc/src/sys/xattr/lsetxattr.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Function declaration of lsetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_LSETXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_LSETXATTR_H
+
+#include "hdr/types/size_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int lsetxattr(const char *path, const char *name, const void *value,
+ size_t size, int flags);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_LSETXATTR_H
diff --git a/libc/src/sys/xattr/setxattr.h b/libc/src/sys/xattr/setxattr.h
new file mode 100644
index 0000000000000..87e1bfe5f2d14
--- /dev/null
+++ b/libc/src/sys/xattr/setxattr.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Function declaration of setxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_SETXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_SETXATTR_H
+
+#include "hdr/types/size_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int setxattr(const char *path, const char *name, const void *value, size_t size,
+ int flags);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_SETXATTR_H
diff --git a/libc/test/src/sys/xattr/CMakeLists.txt b/libc/test/src/sys/xattr/CMakeLists.txt
index 240cb2cc9c7a7..80adc0ec66268 100644
--- a/libc/test/src/sys/xattr/CMakeLists.txt
+++ b/libc/test/src/sys/xattr/CMakeLists.txt
@@ -1,5 +1,70 @@
add_custom_target(libc_sys_xattr_unittests)
+add_libc_test(
+ fgetxattr_test
+ SUITE
+ libc_sys_xattr_unittests
+ SRCS
+ fgetxattr_test.cpp
+ DEPENDS
+ libc.hdr.sys_stat_macros
+ libc.include.sys_xattr
+ libc.src.__support.CPP.scope
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.libc_errno
+ libc.src.errno.errno
+ libc.src.fcntl.creat
+ libc.src.sys.xattr.fgetxattr
+ libc.src.unistd.close
+ libc.src.unistd.unlink
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
+add_libc_test(
+ getxattr_test
+ SUITE
+ libc_sys_xattr_unittests
+ SRCS
+ getxattr_test.cpp
+ DEPENDS
+ libc.hdr.sys_stat_macros
+ libc.include.sys_xattr
+ libc.src.__support.CPP.scope
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.libc_errno
+ libc.src.errno.errno
+ libc.src.fcntl.creat
+ libc.src.sys.xattr.getxattr
+ libc.src.unistd.close
+ libc.src.unistd.symlink
+ libc.src.unistd.unlink
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
+add_libc_test(
+ lgetxattr_test
+ SUITE
+ libc_sys_xattr_unittests
+ SRCS
+ lgetxattr_test.cpp
+ DEPENDS
+ libc.hdr.sys_stat_macros
+ libc.include.sys_xattr
+ libc.src.__support.CPP.scope
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.libc_errno
+ libc.src.errno.errno
+ libc.src.fcntl.creat
+ libc.src.sys.xattr.lgetxattr
+ libc.src.unistd.close
+ libc.src.unistd.symlink
+ libc.src.unistd.unlink
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
add_libc_test(
flistxattr_test
SUITE
@@ -21,6 +86,75 @@ add_libc_test(
libc.test.UnitTest.ErrnoSetterMatcher
)
+add_libc_test(
+ setxattr_test
+ SUITE
+ libc_sys_xattr_unittests
+ SRCS
+ setxattr_test.cpp
+ DEPENDS
+ libc.hdr.sys_stat_macros
+ libc.hdr.sys_xattr_macros
+ libc.hdr.types.ssize_t
+ libc.include.sys_xattr
+ libc.src.__support.CPP.scope
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.libc_errno
+ libc.src.errno.errno
+ libc.src.fcntl.creat
+ libc.src.sys.xattr.setxattr
+ libc.src.unistd.close
+ libc.src.unistd.symlink
+ libc.src.unistd.unlink
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
+add_libc_test(
+ lsetxattr_test
+ SUITE
+ libc_sys_xattr_unittests
+ SRCS
+ lsetxattr_test.cpp
+ DEPENDS
+ libc.hdr.sys_stat_macros
+ libc.hdr.sys_xattr_macros
+ libc.hdr.types.ssize_t
+ libc.include.sys_xattr
+ libc.src.__support.CPP.scope
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.libc_errno
+ libc.src.errno.errno
+ libc.src.fcntl.creat
+ libc.src.sys.xattr.lsetxattr
+ libc.src.unistd.close
+ libc.src.unistd.unlink
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
+add_libc_test(
+ fsetxattr_test
+ SUITE
+ libc_sys_xattr_unittests
+ SRCS
+ fsetxattr_test.cpp
+ DEPENDS
+ libc.hdr.sys_stat_macros
+ libc.hdr.sys_xattr_macros
+ libc.include.sys_xattr
+ libc.src.__support.CPP.scope
+ libc.src.__support.OSUtil.osutil
+ libc.src.__support.libc_errno
+ libc.src.errno.errno
+ libc.src.fcntl.creat
+ libc.src.sys.xattr.fsetxattr
+ libc.src.unistd.close
+ libc.src.unistd.unlink
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
add_libc_test(
listxattr_test
SUITE
diff --git a/libc/test/src/sys/xattr/fgetxattr_test.cpp b/libc/test/src/sys/xattr/fgetxattr_test.cpp
new file mode 100644
index 0000000000000..28846f0d722d0
--- /dev/null
+++ b/libc/test/src/sys/xattr/fgetxattr_test.cpp
@@ -0,0 +1,123 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for fgetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/sys_stat_macros.h"
+#include "src/__support/CPP/scope.h"
+#include "src/__support/OSUtil/linux/syscall.h"
+#include "src/__support/libc_errno.h"
+#include "src/fcntl/creat.h"
+#include "src/sys/xattr/fgetxattr.h"
+#include "src/unistd/close.h"
+#include "src/unistd/unlink.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+#include <sys/syscall.h>
+
+namespace {
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LlvmLibcFgetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::cpp::scope_exit;
+using LIBC_NAMESPACE::cpp::string_view;
+
+int recreate_test_file(const char *path) {
+ LIBC_NAMESPACE::unlink(path);
+ LIBC_NAMESPACE::libc_errno = 0;
+ return LIBC_NAMESPACE::creat(path, S_IRWXU);
+}
+
+TEST_F(LlvmLibcFgetxattrTest, WithUserExtendedAttribute) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fgetxattr.txt");
+
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ string_view XATTR_NAME = "user.test_attr";
+ string_view XATTR_VALUE = "test_value";
+ ASSERT_EQ(0, LIBC_NAMESPACE::syscall_impl<int>(
+ SYS_setxattr, static_cast<const char *>(TEST_FILE_NAME),
+ XATTR_NAME.data(), XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ 0));
+
+ EXPECT_THAT(LIBC_NAMESPACE::fgetxattr(fd, XATTR_NAME.data(), nullptr, 0),
+ Succeeds<ssize_t>(XATTR_VALUE.size()));
+
+ {
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+
+ char buffer[BUFFER_SIZE] = {};
+ ASSERT_THAT(
+ LIBC_NAMESPACE::fgetxattr(fd, XATTR_NAME.data(), buffer, BUFFER_SIZE),
+ Succeeds(XATTR_VALUE.size()));
+ string_view result_str(buffer, XATTR_VALUE.size());
+ EXPECT_EQ(result_str, XATTR_VALUE);
+ }
+
+ // Call with insufficient buffer size and missing attribute to check failing
+ // errno.
+ {
+ constexpr size_t BUFFER_SIZE = 8;
+ ASSERT_LT(BUFFER_SIZE, XATTR_VALUE.size());
+
+ char buffer[BUFFER_SIZE] = {};
+ EXPECT_THAT(
+ LIBC_NAMESPACE::fgetxattr(fd, XATTR_NAME.data(), buffer, BUFFER_SIZE),
+ Fails<ssize_t>(ERANGE));
+ EXPECT_THAT(LIBC_NAMESPACE::fgetxattr(fd, "user.missing_test_attr", buffer,
+ BUFFER_SIZE),
+ Fails<ssize_t>(ENODATA));
+ }
+}
+
+#if defined(LIBC_ADD_NULL_CHECKS)
+
+TEST(LlvmLibcFgetxattrTest, CrashOnNullAttributeName) {
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ EXPECT_DEATH(
+ [fd] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::fgetxattr(fd, nullptr, buffer, BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST(LlvmLibcFgetxattrTest, CrashOnNullBufferNonZeroSize) {
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ EXPECT_DEATH(
+ [fd] { LIBC_NAMESPACE::fgetxattr(fd, "user.attr", nullptr, 32); },
+ WITH_SIGNAL(-1));
+}
+
+#endif // LIBC_ADD_NULL_CHECKS
+
+} // namespace
diff --git a/libc/test/src/sys/xattr/fsetxattr_test.cpp b/libc/test/src/sys/xattr/fsetxattr_test.cpp
new file mode 100644
index 0000000000000..4a5d78f18d54f
--- /dev/null
+++ b/libc/test/src/sys/xattr/fsetxattr_test.cpp
@@ -0,0 +1,158 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for fsetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/sys_stat_macros.h"
+#include "hdr/sys_xattr_macros.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/CPP/scope.h"
+#include "src/__support/OSUtil/linux/syscall.h"
+#include "src/__support/libc_errno.h"
+#include "src/fcntl/creat.h"
+#include "src/sys/xattr/fsetxattr.h"
+#include "src/unistd/close.h"
+#include "src/unistd/unlink.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+#include <sys/syscall.h>
+
+namespace {
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LlvmLibcLSetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::cpp::scope_exit;
+using LIBC_NAMESPACE::cpp::string_view;
+
+int recreate_test_file(const char *path) {
+ LIBC_NAMESPACE::unlink(path);
+ LIBC_NAMESPACE::libc_errno = 0;
+ return LIBC_NAMESPACE::creat(path, S_IRWXU);
+}
+
+TEST_F(LlvmLibcLSetxattrTest, SetAttributeDefaultFlags) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fsetxattr_default_flags.txt");
+
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ string_view XATTR_NAME = "user.test_attr";
+ string_view XATTR_VALUE = "test_value";
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+ char buffer[BUFFER_SIZE] = {};
+
+ ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ 0),
+ Succeeds(0));
+
+ ASSERT_EQ(static_cast<ssize_t>(XATTR_VALUE.size()),
+ LIBC_NAMESPACE::syscall_impl<ssize_t>(
+ SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
+ XATTR_NAME.data(), buffer, BUFFER_SIZE));
+ EXPECT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
+}
+
+TEST_F(LlvmLibcLSetxattrTest, SetAttributeWithNonzeroFlags) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fsetxattr_nonzero_flags.txt");
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ string_view XATTR_NAME = "user.test_attr";
+ string_view XATTR_VALUE = "test_value";
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+ char buffer[BUFFER_SIZE] = {};
+
+ // Try replace-only before attribute exists.
+ ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ XATTR_REPLACE),
+ Fails(ENODATA));
+
+ ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ XATTR_CREATE),
+ Succeeds(0));
+
+ ASSERT_EQ(static_cast<ssize_t>(XATTR_VALUE.size()),
+ LIBC_NAMESPACE::syscall_impl<ssize_t>(
+ SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
+ XATTR_NAME.data(), buffer, BUFFER_SIZE));
+ ASSERT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
+
+ // Replace-only now that the attribute exists.
+ string_view NEW_XATTR_VALUE = "new_test_value";
+ ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
+ NEW_XATTR_VALUE.data(),
+ NEW_XATTR_VALUE.size(), XATTR_REPLACE),
+ Succeeds(0));
+
+ ASSERT_EQ(static_cast<ssize_t>(NEW_XATTR_VALUE.size()),
+ LIBC_NAMESPACE::syscall_impl<ssize_t>(
+ SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
+ XATTR_NAME.data(), buffer, BUFFER_SIZE));
+ ASSERT_EQ(string_view(buffer, NEW_XATTR_VALUE.size()), NEW_XATTR_VALUE);
+
+ // Try create-only when the attribute already exists.
+ ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ XATTR_CREATE),
+ Fails(EEXIST));
+}
+
+#if defined(LIBC_ADD_NULL_CHECKS)
+
+TEST(LlvmLibcLSetxattrTest, CrashOnNullAttributeName) {
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ EXPECT_DEATH(
+ [fd] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::fsetxattr(fd, nullptr, buffer, BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST(LlvmLibcLSetxattrTest, CrashOnNullBufferNonZeroSize) {
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ EXPECT_DEATH(
+ [fd] { LIBC_NAMESPACE::fsetxattr(fd, "user.attr", nullptr, 32); },
+ WITH_SIGNAL(-1));
+}
+
+#endif // LIBC_ADD_NULL_CHECKS
+
+} // namespace
diff --git a/libc/test/src/sys/xattr/getxattr_test.cpp b/libc/test/src/sys/xattr/getxattr_test.cpp
new file mode 100644
index 0000000000000..f9ce87af5e448
--- /dev/null
+++ b/libc/test/src/sys/xattr/getxattr_test.cpp
@@ -0,0 +1,158 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for getxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/sys_stat_macros.h"
+#include "src/__support/CPP/scope.h"
+#include "src/__support/OSUtil/linux/syscall.h"
+#include "src/__support/libc_errno.h"
+#include "src/fcntl/creat.h"
+#include "src/sys/xattr/getxattr.h"
+#include "src/unistd/close.h"
+#include "src/unistd/symlink.h"
+#include "src/unistd/unlink.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+#include <sys/syscall.h>
+
+namespace {
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LlvmLibcGetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::cpp::scope_exit;
+using LIBC_NAMESPACE::cpp::string_view;
+
+int recreate_test_file(const char *path) {
+ LIBC_NAMESPACE::unlink(path);
+ LIBC_NAMESPACE::libc_errno = 0;
+ return LIBC_NAMESPACE::creat(path, S_IRWXU);
+}
+
+int recreate_test_symlink(const char *target, const char *linkpath) {
+ LIBC_NAMESPACE::unlink(linkpath);
+ LIBC_NAMESPACE::libc_errno = 0;
+ return LIBC_NAMESPACE::symlink(target, linkpath);
+}
+
+TEST_F(LlvmLibcGetxattrTest, WithUserExtendedAttribute) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/getxattr.txt");
+ constexpr const char *TEST_SYMLINK_TARGET = "getxattr.txt";
+ const LIBC_NAMESPACE::CString TEST_SYMLINK_NAME =
+ libc_make_test_file_path("testdata/getxattr_symlink.txt");
+
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+
+ ASSERT_THAT(recreate_test_symlink(TEST_SYMLINK_TARGET, TEST_SYMLINK_NAME),
+ Succeeds(0));
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_SYMLINK_NAME), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ string_view XATTR_NAME = "user.test_attr";
+ string_view XATTR_VALUE = "test_value";
+ ASSERT_EQ(0, LIBC_NAMESPACE::syscall_impl<int>(
+ SYS_setxattr, static_cast<const char *>(TEST_FILE_NAME),
+ XATTR_NAME.data(), XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ 0));
+
+ // Call with the test file path.
+ {
+ EXPECT_THAT(
+ LIBC_NAMESPACE::getxattr(TEST_FILE_NAME, XATTR_NAME.data(), nullptr, 0),
+ Succeeds<ssize_t>(XATTR_VALUE.size()));
+
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+
+ char buffer[BUFFER_SIZE] = {};
+ ASSERT_THAT(LIBC_NAMESPACE::getxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Succeeds(XATTR_VALUE.size()));
+ string_view result_str(buffer, XATTR_VALUE.size());
+ EXPECT_EQ(result_str, XATTR_VALUE);
+ }
+
+ // Call with the symlink path to verify the correct syscall is used
+ // internally; getxattr instead of lgetxattr.
+ {
+ EXPECT_THAT(LIBC_NAMESPACE::getxattr(TEST_SYMLINK_NAME, XATTR_NAME.data(),
+ nullptr, 0),
+ Succeeds<ssize_t>(XATTR_VALUE.size()));
+
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+
+ char buffer[BUFFER_SIZE] = {};
+ ASSERT_THAT(LIBC_NAMESPACE::getxattr(TEST_SYMLINK_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Succeeds(XATTR_VALUE.size()));
+ string_view result_str(buffer, XATTR_VALUE.size());
+ EXPECT_EQ(result_str, XATTR_VALUE);
+ }
+
+ // Call with insufficient buffer size and missing attribute to check failing
+ // errno.
+ {
+ constexpr size_t BUFFER_SIZE = 8;
+ ASSERT_LT(BUFFER_SIZE, XATTR_VALUE.size());
+
+ char buffer[BUFFER_SIZE] = {};
+
+ EXPECT_THAT(LIBC_NAMESPACE::getxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Fails<ssize_t>(ERANGE));
+ EXPECT_THAT(LIBC_NAMESPACE::getxattr(TEST_FILE_NAME,
+ "user.missing_test_attr", buffer,
+ BUFFER_SIZE),
+ Fails<ssize_t>(ENODATA));
+ }
+}
+
+#if defined(LIBC_ADD_NULL_CHECKS)
+
+TEST(LlvmLibcGetxattrTest, CrashOnNullPath) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::getxattr(nullptr, "user.attr", buffer, BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST(LlvmLibcGetxattrTest, CrashOnNullAttributeName) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::getxattr("testdata/file.txt", nullptr, buffer,
+ BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST(LlvmLibcGetxattrTest, CrashOnNullBufferNonZeroSize) {
+ EXPECT_DEATH(
+ [] {
+ LIBC_NAMESPACE::getxattr("testdata/file.txt", "user.attr", nullptr, 32);
+ },
+ WITH_SIGNAL(-1));
+}
+
+#endif // LIBC_ADD_NULL_CHECKS
+
+} // namespace
diff --git a/libc/test/src/sys/xattr/lgetxattr_test.cpp b/libc/test/src/sys/xattr/lgetxattr_test.cpp
new file mode 100644
index 0000000000000..fb0273f45b49d
--- /dev/null
+++ b/libc/test/src/sys/xattr/lgetxattr_test.cpp
@@ -0,0 +1,148 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for lgetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/sys_stat_macros.h"
+#include "src/__support/CPP/scope.h"
+#include "src/__support/OSUtil/linux/syscall.h"
+#include "src/__support/libc_errno.h"
+#include "src/fcntl/creat.h"
+#include "src/sys/xattr/lgetxattr.h"
+#include "src/unistd/close.h"
+#include "src/unistd/symlink.h"
+#include "src/unistd/unlink.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+#include <sys/syscall.h>
+
+namespace {
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LlvmLibcLGetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::cpp::scope_exit;
+using LIBC_NAMESPACE::cpp::string_view;
+
+int recreate_test_file(const char *path) {
+ LIBC_NAMESPACE::unlink(path);
+ LIBC_NAMESPACE::libc_errno = 0;
+ return LIBC_NAMESPACE::creat(path, S_IRWXU);
+}
+
+int recreate_test_symlink(const char *target, const char *linkpath) {
+ LIBC_NAMESPACE::unlink(linkpath);
+ LIBC_NAMESPACE::libc_errno = 0;
+ return LIBC_NAMESPACE::symlink(target, linkpath);
+}
+
+TEST_F(LlvmLibcLGetxattrTest, WithUserExtendedAttribute) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/lgetxattr.txt");
+ constexpr const char *TEST_SYMLINK_TARGET = "lgetxattr.txt";
+ const LIBC_NAMESPACE::CString TEST_SYMLINK_NAME =
+ libc_make_test_file_path("testdata/lgetxattr_symlink.txt");
+
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+
+ ASSERT_THAT(recreate_test_symlink(TEST_SYMLINK_TARGET, TEST_SYMLINK_NAME),
+ Succeeds(0));
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_SYMLINK_NAME), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ string_view XATTR_NAME = "user.test_attr";
+ string_view XATTR_VALUE = "test_value";
+ ASSERT_EQ(0, LIBC_NAMESPACE::syscall_impl<int>(
+ SYS_setxattr, static_cast<const char *>(TEST_FILE_NAME),
+ XATTR_NAME.data(), XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ 0));
+
+ // Call with the test file path.
+ {
+ EXPECT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ nullptr, 0),
+ Succeeds<ssize_t>(XATTR_VALUE.size()));
+
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+
+ char buffer[BUFFER_SIZE] = {};
+ ASSERT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Succeeds(XATTR_VALUE.size()));
+ string_view result_str(buffer, XATTR_VALUE.size());
+ EXPECT_EQ(result_str, XATTR_VALUE);
+ }
+
+ // Call with the symlink path to verify the correct syscall is used
+ // internally; lgetxattr instead of getxattr.
+ {
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+
+ char buffer[BUFFER_SIZE] = {};
+ EXPECT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_SYMLINK_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Fails<ssize_t>(ENODATA));
+ }
+
+ // Call with insufficient buffer size to check failing errno.
+ {
+ constexpr size_t BUFFER_SIZE = 8;
+ ASSERT_LT(BUFFER_SIZE, XATTR_VALUE.size());
+
+ char buffer[BUFFER_SIZE] = {};
+
+ EXPECT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Fails<ssize_t>(ERANGE));
+ }
+}
+
+#if defined(LIBC_ADD_NULL_CHECKS)
+
+TEST(LlvmLibcLGetxattrTest, CrashOnNullPath) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::lgetxattr(nullptr, "user.attr", buffer, BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST(LlvmLibcLGetxattrTest, CrashOnNullAttributeName) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::lgetxattr("testdata/file.txt", nullptr, buffer,
+ BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST(LlvmLibcLGetxattrTest, CrashOnNullBufferNonZeroSize) {
+ EXPECT_DEATH(
+ [] {
+ LIBC_NAMESPACE::lgetxattr("testdata/file.txt", "user.attr", nullptr,
+ 32);
+ },
+ WITH_SIGNAL(-1));
+}
+
+#endif // LIBC_ADD_NULL_CHECKS
+
+} // namespace
diff --git a/libc/test/src/sys/xattr/lsetxattr_test.cpp b/libc/test/src/sys/xattr/lsetxattr_test.cpp
new file mode 100644
index 0000000000000..fa770c8e7e2fc
--- /dev/null
+++ b/libc/test/src/sys/xattr/lsetxattr_test.cpp
@@ -0,0 +1,164 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for lsetxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/sys_stat_macros.h"
+#include "hdr/sys_xattr_macros.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/CPP/scope.h"
+#include "src/__support/OSUtil/linux/syscall.h"
+#include "src/__support/libc_errno.h"
+#include "src/fcntl/creat.h"
+#include "src/sys/xattr/lsetxattr.h"
+#include "src/unistd/close.h"
+#include "src/unistd/unlink.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+#include <sys/syscall.h>
+
+namespace {
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LlvmLibcLSetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::cpp::scope_exit;
+using LIBC_NAMESPACE::cpp::string_view;
+
+int recreate_test_file(const char *path) {
+ LIBC_NAMESPACE::unlink(path);
+ LIBC_NAMESPACE::libc_errno = 0;
+ return LIBC_NAMESPACE::creat(path, S_IRWXU);
+}
+
+TEST_F(LlvmLibcLSetxattrTest, SetAttributeDefaultFlags) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/lsetxattr_default_flags.txt");
+
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ // Set an attribute through the test file name.
+ {
+ string_view XATTR_NAME = "user.test_attr_through_file";
+ string_view XATTR_VALUE = "test_value_through_file";
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+ char buffer[BUFFER_SIZE] = {};
+
+ ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(),
+ XATTR_VALUE.size(),
+ /* flags = */ 0),
+ Succeeds(0));
+
+ ASSERT_EQ(static_cast<ssize_t>(XATTR_VALUE.size()),
+ LIBC_NAMESPACE::syscall_impl<ssize_t>(
+ SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
+ XATTR_NAME.data(), buffer, BUFFER_SIZE));
+ EXPECT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
+ }
+
+ // TODO: Figure out if/how to test `lsetxattr` with a symlink path. The "user"
+ // namespace extended attributes appear restricted to regular files and
+ // directories. Attempting to set a "user" extended attribute on a symlink
+ // results in EPERM.
+}
+
+TEST_F(LlvmLibcLSetxattrTest, SetAttributeWithNonzeroFlags) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/lsetxattr_nonzero_flags.txt");
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+
+ string_view XATTR_NAME = "user.test_attr";
+ string_view XATTR_VALUE = "test_value";
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+ char buffer[BUFFER_SIZE] = {};
+
+ // Try replace-only before attribute exists.
+ ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ XATTR_REPLACE),
+ Fails(ENODATA));
+
+ ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ XATTR_CREATE),
+ Succeeds(0));
+
+ ASSERT_EQ(static_cast<ssize_t>(XATTR_VALUE.size()),
+ LIBC_NAMESPACE::syscall_impl<ssize_t>(
+ SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
+ XATTR_NAME.data(), buffer, BUFFER_SIZE));
+ ASSERT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
+
+ // Replace-only now that the attribute exists.
+ string_view NEW_XATTR_VALUE = "new_test_value";
+ ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ NEW_XATTR_VALUE.data(),
+ NEW_XATTR_VALUE.size(), XATTR_REPLACE),
+ Succeeds(0));
+
+ ASSERT_EQ(static_cast<ssize_t>(NEW_XATTR_VALUE.size()),
+ LIBC_NAMESPACE::syscall_impl<ssize_t>(
+ SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
+ XATTR_NAME.data(), buffer, BUFFER_SIZE));
+ ASSERT_EQ(string_view(buffer, NEW_XATTR_VALUE.size()), NEW_XATTR_VALUE);
+
+ // Try create-only when the attribute already exists.
+ ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ XATTR_CREATE),
+ Fails(EEXIST));
+}
+
+#if defined(LIBC_ADD_NULL_CHECKS)
+
+TEST(LlvmLibcLSetxattrTest, CrashOnNullPath) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::lsetxattr(nullptr, "user.attr", buffer, BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST(LlvmLibcLSetxattrTest, CrashOnNullAttributeName) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::lsetxattr("testdata/file.txt", nullptr, buffer,
+ BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST(LlvmLibcLSetxattrTest, CrashOnNullBufferNonZeroSize) {
+ EXPECT_DEATH(
+ [] {
+ LIBC_NAMESPACE::lsetxattr("testdata/file.txt", "user.attr", nullptr,
+ 32);
+ },
+ WITH_SIGNAL(-1));
+}
+
+#endif // LIBC_ADD_NULL_CHECKS
+
+} // namespace
diff --git a/libc/test/src/sys/xattr/setxattr_test.cpp b/libc/test/src/sys/xattr/setxattr_test.cpp
new file mode 100644
index 0000000000000..1e31cbfc4b28a
--- /dev/null
+++ b/libc/test/src/sys/xattr/setxattr_test.cpp
@@ -0,0 +1,192 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for setxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/sys_stat_macros.h"
+#include "hdr/sys_xattr_macros.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/CPP/scope.h"
+#include "src/__support/OSUtil/linux/syscall.h"
+#include "src/__support/libc_errno.h"
+#include "src/fcntl/creat.h"
+#include "src/sys/xattr/setxattr.h"
+#include "src/unistd/close.h"
+#include "src/unistd/symlink.h"
+#include "src/unistd/unlink.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+#include <sys/syscall.h>
+
+namespace {
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LlvmLibcLSetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::cpp::scope_exit;
+using LIBC_NAMESPACE::cpp::string_view;
+
+int recreate_test_file(const char *path) {
+ LIBC_NAMESPACE::unlink(path);
+ LIBC_NAMESPACE::libc_errno = 0;
+ return LIBC_NAMESPACE::creat(path, S_IRWXU);
+}
+
+int recreate_test_symlink(const char *target, const char *linkpath) {
+ LIBC_NAMESPACE::unlink(linkpath);
+ LIBC_NAMESPACE::libc_errno = 0;
+ return LIBC_NAMESPACE::symlink(target, linkpath);
+}
+
+TEST_F(LlvmLibcLSetxattrTest, SetAttributeDefaultFlags) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/setxattr_default_flags.txt");
+ constexpr const char *TEST_SYMLINK_TARGET = "setxattr_default_flags.txt";
+ const LIBC_NAMESPACE::CString TEST_SYMLINK_NAME =
+ libc_make_test_file_path("testdata/setxattr_default_flags_symlink.txt");
+
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+
+ ASSERT_THAT(recreate_test_symlink(TEST_SYMLINK_TARGET, TEST_SYMLINK_NAME),
+ Succeeds(0));
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_SYMLINK_NAME), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ // Set an attribute through the test file name.
+ {
+ string_view XATTR_NAME = "user.test_attr_through_file";
+ string_view XATTR_VALUE = "test_value_through_file";
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+ char buffer[BUFFER_SIZE] = {};
+
+ ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ 0),
+ Succeeds(0));
+
+ ASSERT_EQ(static_cast<ssize_t>(XATTR_VALUE.size()),
+ LIBC_NAMESPACE::syscall_impl<ssize_t>(
+ SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
+ XATTR_NAME.data(), buffer, BUFFER_SIZE));
+ EXPECT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
+ }
+
+ // Set another attribute through the symlink to verify the correct syscall is
+ // used internally; setxattr instead of lsetxattr.
+ {
+ string_view XATTR_NAME = "user.test_attr_through_symlink";
+ string_view XATTR_VALUE = "test_value_through_symlink";
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+ char buffer[BUFFER_SIZE] = {};
+
+ ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_SYMLINK_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ 0),
+ Succeeds(0));
+
+ EXPECT_EQ(static_cast<ssize_t>(XATTR_VALUE.size()),
+ LIBC_NAMESPACE::syscall_impl<ssize_t>(
+ SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
+ XATTR_NAME.data(), buffer, BUFFER_SIZE));
+ EXPECT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
+ }
+}
+
+TEST_F(LlvmLibcLSetxattrTest, SetAttributeWithNonzeroFlags) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/setxattr_nonzero_flags.txt");
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+
+ string_view XATTR_NAME = "user.test_attr";
+ string_view XATTR_VALUE = "test_value";
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+ char buffer[BUFFER_SIZE] = {};
+
+ // Try replace-only before attribute exists.
+ ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ XATTR_REPLACE),
+ Fails(ENODATA));
+
+ ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ XATTR_CREATE),
+ Succeeds(0));
+
+ ASSERT_EQ(static_cast<ssize_t>(XATTR_VALUE.size()),
+ LIBC_NAMESPACE::syscall_impl<ssize_t>(
+ SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
+ XATTR_NAME.data(), buffer, BUFFER_SIZE));
+ ASSERT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
+
+ // Replace-only now that the attribute exists.
+ string_view NEW_XATTR_VALUE = "new_test_value";
+ ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ NEW_XATTR_VALUE.data(),
+ NEW_XATTR_VALUE.size(), XATTR_REPLACE),
+ Succeeds(0));
+
+ ASSERT_EQ(static_cast<ssize_t>(NEW_XATTR_VALUE.size()),
+ LIBC_NAMESPACE::syscall_impl<ssize_t>(
+ SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
+ XATTR_NAME.data(), buffer, BUFFER_SIZE));
+ ASSERT_EQ(string_view(buffer, NEW_XATTR_VALUE.size()), NEW_XATTR_VALUE);
+
+ // Try create-only when the attribute already exists.
+ ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ XATTR_CREATE),
+ Fails(EEXIST));
+}
+
+#if defined(LIBC_ADD_NULL_CHECKS)
+
+TEST(LlvmLibcLSetxattrTest, CrashOnNullPath) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::setxattr(nullptr, "user.attr", buffer, BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST(LlvmLibcLSetxattrTest, CrashOnNullAttributeName) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::setxattr("testdata/file.txt", nullptr, buffer,
+ BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST(LlvmLibcLSetxattrTest, CrashOnNullBufferNonZeroSize) {
+ EXPECT_DEATH(
+ [] {
+ LIBC_NAMESPACE::setxattr("testdata/file.txt", "user.attr", nullptr, 32);
+ },
+ WITH_SIGNAL(-1));
+}
+
+#endif // LIBC_ADD_NULL_CHECKS
+
+} // namespace
>From a54839c13a61dfff202ffd7de966b10cd5ab2098 Mon Sep 17 00:00:00 2001
From: Alex Strelnikov <strel at google.com>
Date: Fri, 18 Sep 2026 20:08:09 +0000
Subject: [PATCH 2/6] Fix missing null checks
---
libc/src/sys/xattr/linux/fgetxattr.cpp | 2 ++
libc/src/sys/xattr/linux/getxattr.cpp | 2 ++
libc/src/sys/xattr/linux/lgetxattr.cpp | 2 ++
3 files changed, 6 insertions(+)
diff --git a/libc/src/sys/xattr/linux/fgetxattr.cpp b/libc/src/sys/xattr/linux/fgetxattr.cpp
index b7ee5c9fe2e78..cf4da7f98cbf6 100644
--- a/libc/src/sys/xattr/linux/fgetxattr.cpp
+++ b/libc/src/sys/xattr/linux/fgetxattr.cpp
@@ -23,6 +23,8 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(ssize_t, fgetxattr,
(int fd, const char *name, void *value, size_t size)) {
LIBC_CRASH_ON_NULLPTR(name);
+ if (size != 0)
+ LIBC_CRASH_ON_NULLPTR(value);
ErrorOr<ssize_t> ret = linux_syscalls::fgetxattr(fd, name, value, size);
if (!ret) {
diff --git a/libc/src/sys/xattr/linux/getxattr.cpp b/libc/src/sys/xattr/linux/getxattr.cpp
index d4f9361b8613b..1080158465800 100644
--- a/libc/src/sys/xattr/linux/getxattr.cpp
+++ b/libc/src/sys/xattr/linux/getxattr.cpp
@@ -25,6 +25,8 @@ LLVM_LIBC_FUNCTION(ssize_t, getxattr,
size_t size)) {
LIBC_CRASH_ON_NULLPTR(path);
LIBC_CRASH_ON_NULLPTR(name);
+ if (size != 0)
+ LIBC_CRASH_ON_NULLPTR(value);
ErrorOr<ssize_t> ret = linux_syscalls::getxattr(path, name, value, size);
if (!ret) {
diff --git a/libc/src/sys/xattr/linux/lgetxattr.cpp b/libc/src/sys/xattr/linux/lgetxattr.cpp
index 0e9885f1e5cad..da3ef91e01a81 100644
--- a/libc/src/sys/xattr/linux/lgetxattr.cpp
+++ b/libc/src/sys/xattr/linux/lgetxattr.cpp
@@ -25,6 +25,8 @@ LLVM_LIBC_FUNCTION(ssize_t, lgetxattr,
size_t size)) {
LIBC_CRASH_ON_NULLPTR(path);
LIBC_CRASH_ON_NULLPTR(name);
+ if (size != 0)
+ LIBC_CRASH_ON_NULLPTR(value);
ErrorOr<ssize_t> ret = linux_syscalls::lgetxattr(path, name, value, size);
if (!ret) {
>From e189225fa3afbb2a170d6e5856315c46cb562a98 Mon Sep 17 00:00:00 2001
From: Alex Strelnikov <strel at google.com>
Date: Fri, 18 Sep 2026 20:15:58 +0000
Subject: [PATCH 3/6] Fix up test names
---
libc/test/src/sys/xattr/fgetxattr_test.cpp | 4 ++--
libc/test/src/sys/xattr/fsetxattr_test.cpp | 10 +++++-----
libc/test/src/sys/xattr/getxattr_test.cpp | 6 +++---
libc/test/src/sys/xattr/lgetxattr_test.cpp | 10 +++++-----
libc/test/src/sys/xattr/lsetxattr_test.cpp | 12 ++++++------
libc/test/src/sys/xattr/setxattr_test.cpp | 12 ++++++------
6 files changed, 27 insertions(+), 27 deletions(-)
diff --git a/libc/test/src/sys/xattr/fgetxattr_test.cpp b/libc/test/src/sys/xattr/fgetxattr_test.cpp
index 28846f0d722d0..a4fde52fb8634 100644
--- a/libc/test/src/sys/xattr/fgetxattr_test.cpp
+++ b/libc/test/src/sys/xattr/fgetxattr_test.cpp
@@ -88,7 +88,7 @@ TEST_F(LlvmLibcFgetxattrTest, WithUserExtendedAttribute) {
#if defined(LIBC_ADD_NULL_CHECKS)
-TEST(LlvmLibcFgetxattrTest, CrashOnNullAttributeName) {
+TEST_F(LlvmLibcFgetxattrTest, CrashOnNullAttributeName) {
int fd = recreate_test_file(TEST_FILE_NAME);
ASSERT_ERRNO_SUCCESS();
scope_exit cleanup([&] {
@@ -105,7 +105,7 @@ TEST(LlvmLibcFgetxattrTest, CrashOnNullAttributeName) {
WITH_SIGNAL(-1));
}
-TEST(LlvmLibcFgetxattrTest, CrashOnNullBufferNonZeroSize) {
+TEST_F(LlvmLibcFgetxattrTest, CrashOnNullBufferNonZeroSize) {
int fd = recreate_test_file(TEST_FILE_NAME);
ASSERT_ERRNO_SUCCESS();
scope_exit cleanup([&] {
diff --git a/libc/test/src/sys/xattr/fsetxattr_test.cpp b/libc/test/src/sys/xattr/fsetxattr_test.cpp
index 4a5d78f18d54f..436042c7f2605 100644
--- a/libc/test/src/sys/xattr/fsetxattr_test.cpp
+++ b/libc/test/src/sys/xattr/fsetxattr_test.cpp
@@ -29,7 +29,7 @@
namespace {
using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
-using LlvmLibcLSetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LlvmLibcFsetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
using LIBC_NAMESPACE::cpp::scope_exit;
using LIBC_NAMESPACE::cpp::string_view;
@@ -39,7 +39,7 @@ int recreate_test_file(const char *path) {
return LIBC_NAMESPACE::creat(path, S_IRWXU);
}
-TEST_F(LlvmLibcLSetxattrTest, SetAttributeDefaultFlags) {
+TEST_F(LlvmLibcFsetxattrTest, SetAttributeDefaultFlags) {
const LIBC_NAMESPACE::CString TEST_FILE_NAME =
libc_make_test_file_path("testdata/fsetxattr_default_flags.txt");
@@ -68,7 +68,7 @@ TEST_F(LlvmLibcLSetxattrTest, SetAttributeDefaultFlags) {
EXPECT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
}
-TEST_F(LlvmLibcLSetxattrTest, SetAttributeWithNonzeroFlags) {
+TEST_F(LlvmLibcFsetxattrTest, SetAttributeWithNonzeroFlags) {
const LIBC_NAMESPACE::CString TEST_FILE_NAME =
libc_make_test_file_path("testdata/fsetxattr_nonzero_flags.txt");
int fd = recreate_test_file(TEST_FILE_NAME);
@@ -123,7 +123,7 @@ TEST_F(LlvmLibcLSetxattrTest, SetAttributeWithNonzeroFlags) {
#if defined(LIBC_ADD_NULL_CHECKS)
-TEST(LlvmLibcLSetxattrTest, CrashOnNullAttributeName) {
+TEST_F(LlvmLibcFsetxattrTest, CrashOnNullAttributeName) {
int fd = recreate_test_file(TEST_FILE_NAME);
ASSERT_ERRNO_SUCCESS();
scope_exit cleanup([&] {
@@ -140,7 +140,7 @@ TEST(LlvmLibcLSetxattrTest, CrashOnNullAttributeName) {
WITH_SIGNAL(-1));
}
-TEST(LlvmLibcLSetxattrTest, CrashOnNullBufferNonZeroSize) {
+TEST_F(LlvmLibcFsetxattrTest, CrashOnNullBufferNonZeroSize) {
int fd = recreate_test_file(TEST_FILE_NAME);
ASSERT_ERRNO_SUCCESS();
scope_exit cleanup([&] {
diff --git a/libc/test/src/sys/xattr/getxattr_test.cpp b/libc/test/src/sys/xattr/getxattr_test.cpp
index f9ce87af5e448..73df59d85e30b 100644
--- a/libc/test/src/sys/xattr/getxattr_test.cpp
+++ b/libc/test/src/sys/xattr/getxattr_test.cpp
@@ -124,7 +124,7 @@ TEST_F(LlvmLibcGetxattrTest, WithUserExtendedAttribute) {
#if defined(LIBC_ADD_NULL_CHECKS)
-TEST(LlvmLibcGetxattrTest, CrashOnNullPath) {
+TEST_F(LlvmLibcGetxattrTest, CrashOnNullPath) {
EXPECT_DEATH(
[] {
constexpr size_t BUFFER_SIZE = 32;
@@ -134,7 +134,7 @@ TEST(LlvmLibcGetxattrTest, CrashOnNullPath) {
WITH_SIGNAL(-1));
}
-TEST(LlvmLibcGetxattrTest, CrashOnNullAttributeName) {
+TEST_F(LlvmLibcGetxattrTest, CrashOnNullAttributeName) {
EXPECT_DEATH(
[] {
constexpr size_t BUFFER_SIZE = 32;
@@ -145,7 +145,7 @@ TEST(LlvmLibcGetxattrTest, CrashOnNullAttributeName) {
WITH_SIGNAL(-1));
}
-TEST(LlvmLibcGetxattrTest, CrashOnNullBufferNonZeroSize) {
+TEST_F(LlvmLibcGetxattrTest, CrashOnNullBufferNonZeroSize) {
EXPECT_DEATH(
[] {
LIBC_NAMESPACE::getxattr("testdata/file.txt", "user.attr", nullptr, 32);
diff --git a/libc/test/src/sys/xattr/lgetxattr_test.cpp b/libc/test/src/sys/xattr/lgetxattr_test.cpp
index fb0273f45b49d..dbddcbe435a24 100644
--- a/libc/test/src/sys/xattr/lgetxattr_test.cpp
+++ b/libc/test/src/sys/xattr/lgetxattr_test.cpp
@@ -28,7 +28,7 @@
namespace {
using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
-using LlvmLibcLGetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LlvmLibcLgetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
using LIBC_NAMESPACE::cpp::scope_exit;
using LIBC_NAMESPACE::cpp::string_view;
@@ -44,7 +44,7 @@ int recreate_test_symlink(const char *target, const char *linkpath) {
return LIBC_NAMESPACE::symlink(target, linkpath);
}
-TEST_F(LlvmLibcLGetxattrTest, WithUserExtendedAttribute) {
+TEST_F(LlvmLibcLgetxattrTest, WithUserExtendedAttribute) {
const LIBC_NAMESPACE::CString TEST_FILE_NAME =
libc_make_test_file_path("testdata/lgetxattr.txt");
constexpr const char *TEST_SYMLINK_TARGET = "lgetxattr.txt";
@@ -113,7 +113,7 @@ TEST_F(LlvmLibcLGetxattrTest, WithUserExtendedAttribute) {
#if defined(LIBC_ADD_NULL_CHECKS)
-TEST(LlvmLibcLGetxattrTest, CrashOnNullPath) {
+TEST_F(LlvmLibcLgetxattrTest, CrashOnNullPath) {
EXPECT_DEATH(
[] {
constexpr size_t BUFFER_SIZE = 32;
@@ -123,7 +123,7 @@ TEST(LlvmLibcLGetxattrTest, CrashOnNullPath) {
WITH_SIGNAL(-1));
}
-TEST(LlvmLibcLGetxattrTest, CrashOnNullAttributeName) {
+TEST_F(LlvmLibcLgetxattrTest, CrashOnNullAttributeName) {
EXPECT_DEATH(
[] {
constexpr size_t BUFFER_SIZE = 32;
@@ -134,7 +134,7 @@ TEST(LlvmLibcLGetxattrTest, CrashOnNullAttributeName) {
WITH_SIGNAL(-1));
}
-TEST(LlvmLibcLGetxattrTest, CrashOnNullBufferNonZeroSize) {
+TEST_F(LlvmLibcLgetxattrTest, CrashOnNullBufferNonZeroSize) {
EXPECT_DEATH(
[] {
LIBC_NAMESPACE::lgetxattr("testdata/file.txt", "user.attr", nullptr,
diff --git a/libc/test/src/sys/xattr/lsetxattr_test.cpp b/libc/test/src/sys/xattr/lsetxattr_test.cpp
index fa770c8e7e2fc..57f95ba75cab5 100644
--- a/libc/test/src/sys/xattr/lsetxattr_test.cpp
+++ b/libc/test/src/sys/xattr/lsetxattr_test.cpp
@@ -29,7 +29,7 @@
namespace {
using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
-using LlvmLibcLSetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LlvmLibcLsetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
using LIBC_NAMESPACE::cpp::scope_exit;
using LIBC_NAMESPACE::cpp::string_view;
@@ -39,7 +39,7 @@ int recreate_test_file(const char *path) {
return LIBC_NAMESPACE::creat(path, S_IRWXU);
}
-TEST_F(LlvmLibcLSetxattrTest, SetAttributeDefaultFlags) {
+TEST_F(LlvmLibcLsetxattrTest, SetAttributeDefaultFlags) {
const LIBC_NAMESPACE::CString TEST_FILE_NAME =
libc_make_test_file_path("testdata/lsetxattr_default_flags.txt");
@@ -77,7 +77,7 @@ TEST_F(LlvmLibcLSetxattrTest, SetAttributeDefaultFlags) {
// results in EPERM.
}
-TEST_F(LlvmLibcLSetxattrTest, SetAttributeWithNonzeroFlags) {
+TEST_F(LlvmLibcLsetxattrTest, SetAttributeWithNonzeroFlags) {
const LIBC_NAMESPACE::CString TEST_FILE_NAME =
libc_make_test_file_path("testdata/lsetxattr_nonzero_flags.txt");
int fd = recreate_test_file(TEST_FILE_NAME);
@@ -129,7 +129,7 @@ TEST_F(LlvmLibcLSetxattrTest, SetAttributeWithNonzeroFlags) {
#if defined(LIBC_ADD_NULL_CHECKS)
-TEST(LlvmLibcLSetxattrTest, CrashOnNullPath) {
+TEST_F(LlvmLibcLsetxattrTest, CrashOnNullPath) {
EXPECT_DEATH(
[] {
constexpr size_t BUFFER_SIZE = 32;
@@ -139,7 +139,7 @@ TEST(LlvmLibcLSetxattrTest, CrashOnNullPath) {
WITH_SIGNAL(-1));
}
-TEST(LlvmLibcLSetxattrTest, CrashOnNullAttributeName) {
+TEST_F(LlvmLibcLsetxattrTest, CrashOnNullAttributeName) {
EXPECT_DEATH(
[] {
constexpr size_t BUFFER_SIZE = 32;
@@ -150,7 +150,7 @@ TEST(LlvmLibcLSetxattrTest, CrashOnNullAttributeName) {
WITH_SIGNAL(-1));
}
-TEST(LlvmLibcLSetxattrTest, CrashOnNullBufferNonZeroSize) {
+TEST_F(LlvmLibcLsetxattrTest, CrashOnNullBufferNonZeroSize) {
EXPECT_DEATH(
[] {
LIBC_NAMESPACE::lsetxattr("testdata/file.txt", "user.attr", nullptr,
diff --git a/libc/test/src/sys/xattr/setxattr_test.cpp b/libc/test/src/sys/xattr/setxattr_test.cpp
index 1e31cbfc4b28a..c8a0cbe428baa 100644
--- a/libc/test/src/sys/xattr/setxattr_test.cpp
+++ b/libc/test/src/sys/xattr/setxattr_test.cpp
@@ -30,7 +30,7 @@
namespace {
using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
-using LlvmLibcLSetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LlvmLibcSetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
using LIBC_NAMESPACE::cpp::scope_exit;
using LIBC_NAMESPACE::cpp::string_view;
@@ -46,7 +46,7 @@ int recreate_test_symlink(const char *target, const char *linkpath) {
return LIBC_NAMESPACE::symlink(target, linkpath);
}
-TEST_F(LlvmLibcLSetxattrTest, SetAttributeDefaultFlags) {
+TEST_F(LlvmLibcSetxattrTest, SetAttributeDefaultFlags) {
const LIBC_NAMESPACE::CString TEST_FILE_NAME =
libc_make_test_file_path("testdata/setxattr_default_flags.txt");
constexpr const char *TEST_SYMLINK_TARGET = "setxattr_default_flags.txt";
@@ -106,7 +106,7 @@ TEST_F(LlvmLibcLSetxattrTest, SetAttributeDefaultFlags) {
}
}
-TEST_F(LlvmLibcLSetxattrTest, SetAttributeWithNonzeroFlags) {
+TEST_F(LlvmLibcSetxattrTest, SetAttributeWithNonzeroFlags) {
const LIBC_NAMESPACE::CString TEST_FILE_NAME =
libc_make_test_file_path("testdata/setxattr_nonzero_flags.txt");
int fd = recreate_test_file(TEST_FILE_NAME);
@@ -158,7 +158,7 @@ TEST_F(LlvmLibcLSetxattrTest, SetAttributeWithNonzeroFlags) {
#if defined(LIBC_ADD_NULL_CHECKS)
-TEST(LlvmLibcLSetxattrTest, CrashOnNullPath) {
+TEST_F(LlvmLibcSetxattrTest, CrashOnNullPath) {
EXPECT_DEATH(
[] {
constexpr size_t BUFFER_SIZE = 32;
@@ -168,7 +168,7 @@ TEST(LlvmLibcLSetxattrTest, CrashOnNullPath) {
WITH_SIGNAL(-1));
}
-TEST(LlvmLibcLSetxattrTest, CrashOnNullAttributeName) {
+TEST_F(LlvmLibcSetxattrTest, CrashOnNullAttributeName) {
EXPECT_DEATH(
[] {
constexpr size_t BUFFER_SIZE = 32;
@@ -179,7 +179,7 @@ TEST(LlvmLibcLSetxattrTest, CrashOnNullAttributeName) {
WITH_SIGNAL(-1));
}
-TEST(LlvmLibcLSetxattrTest, CrashOnNullBufferNonZeroSize) {
+TEST_F(LlvmLibcSetxattrTest, CrashOnNullBufferNonZeroSize) {
EXPECT_DEATH(
[] {
LIBC_NAMESPACE::setxattr("testdata/file.txt", "user.attr", nullptr, 32);
>From 8216b9b2f01a7d797b8825ef926be1d29b8dcbbc Mon Sep 17 00:00:00 2001
From: Alex Strelnikov <strel at google.com>
Date: Tue, 22 Sep 2026 14:06:50 +0000
Subject: [PATCH 4/6] Update with review fixes.
- Fix fsetxattr arguments in xattr.yaml
- Add missing deps in syscal_wrappers/
- Fix stale header guards in src/sys/xattr/
- Add missing string_view dep in tests
- Fix null check tests
- Split file and symlink scope_cleanups, and add missing ones
---
libc/include/sys/xattr.yaml | 2 +-
.../linux/syscall_wrappers/CMakeLists.txt | 9 +++++++++
.../OSUtil/linux/syscall_wrappers/fgetxattr.h | 2 ++
.../OSUtil/linux/syscall_wrappers/fsetxattr.h | 1 +
.../OSUtil/linux/syscall_wrappers/getxattr.h | 2 ++
.../OSUtil/linux/syscall_wrappers/lgetxattr.h | 2 ++
.../OSUtil/linux/syscall_wrappers/lsetxattr.h | 1 +
.../OSUtil/linux/syscall_wrappers/setxattr.h | 1 +
libc/src/sys/xattr/fgetxattr.h | 6 +++---
libc/src/sys/xattr/flistxattr.h | 6 +++---
libc/src/sys/xattr/fsetxattr.h | 6 +++---
libc/src/sys/xattr/getxattr.h | 6 +++---
libc/src/sys/xattr/lgetxattr.h | 6 +++---
libc/src/sys/xattr/listxattr.h | 6 +++---
libc/src/sys/xattr/llistxattr.h | 6 +++---
libc/src/sys/xattr/lsetxattr.h | 6 +++---
libc/src/sys/xattr/setxattr.h | 6 +++---
libc/test/src/sys/xattr/CMakeLists.txt | 7 +++++++
libc/test/src/sys/xattr/fgetxattr_test.cpp | 5 +++++
libc/test/src/sys/xattr/fsetxattr_test.cpp | 13 +++++++++++--
libc/test/src/sys/xattr/getxattr_test.cpp | 7 +++++--
libc/test/src/sys/xattr/lgetxattr_test.cpp | 7 +++++--
libc/test/src/sys/xattr/lsetxattr_test.cpp | 17 +++++++++++------
libc/test/src/sys/xattr/setxattr_test.cpp | 18 +++++++++++++-----
24 files changed, 103 insertions(+), 45 deletions(-)
diff --git a/libc/include/sys/xattr.yaml b/libc/include/sys/xattr.yaml
index 0f680630c34a6..3d1f30bd43370 100644
--- a/libc/include/sys/xattr.yaml
+++ b/libc/include/sys/xattr.yaml
@@ -64,7 +64,7 @@ functions:
- linux
return_type: int
arguments:
- - type: const char *
+ - type: int
- type: const char *
- type: const void *
- type: size_t
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index 99d1792c85696..f50c656bdf585 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -220,6 +220,8 @@ add_header_library(
HDRS
fgetxattr.h
DEPENDS
+ libc.hdr.types.size_t
+ libc.hdr.types.ssize_t
libc.src.__support.OSUtil.osutil
libc.src.__support.common
libc.src.__support.error_or
@@ -232,6 +234,8 @@ add_header_library(
HDRS
getxattr.h
DEPENDS
+ libc.hdr.types.size_t
+ libc.hdr.types.ssize_t
libc.src.__support.OSUtil.osutil
libc.src.__support.common
libc.src.__support.error_or
@@ -244,6 +248,8 @@ add_header_library(
HDRS
lgetxattr.h
DEPENDS
+ libc.hdr.types.size_t
+ libc.hdr.types.ssize_t
libc.src.__support.OSUtil.osutil
libc.src.__support.common
libc.src.__support.error_or
@@ -256,6 +262,7 @@ add_header_library(
HDRS
fsetxattr.h
DEPENDS
+ libc.hdr.types.size_t
libc.src.__support.OSUtil.osutil
libc.src.__support.common
libc.src.__support.error_or
@@ -268,6 +275,7 @@ add_header_library(
HDRS
setxattr.h
DEPENDS
+ libc.hdr.types.size_t
libc.src.__support.OSUtil.osutil
libc.src.__support.common
libc.src.__support.error_or
@@ -280,6 +288,7 @@ add_header_library(
HDRS
lsetxattr.h
DEPENDS
+ libc.hdr.types.size_t
libc.src.__support.OSUtil.osutil
libc.src.__support.common
libc.src.__support.error_or
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/fgetxattr.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/fgetxattr.h
index e37b9c787f22b..f5c30e1fcd6b6 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/fgetxattr.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/fgetxattr.h
@@ -14,6 +14,8 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FGETXATTR_H
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FGETXATTR_H
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
#include "src/__support/OSUtil/linux/syscall.h"
#include "src/__support/common.h"
#include "src/__support/error_or.h"
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/fsetxattr.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/fsetxattr.h
index cd818266d59a1..81c90978d6204 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/fsetxattr.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/fsetxattr.h
@@ -14,6 +14,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FSETXATTR_H
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FSETXATTR_H
+#include "hdr/types/size_t.h"
#include "src/__support/OSUtil/linux/syscall.h"
#include "src/__support/common.h"
#include "src/__support/error_or.h"
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/getxattr.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/getxattr.h
index cfc532eadfb4a..2e90f4aab0728 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/getxattr.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/getxattr.h
@@ -14,6 +14,8 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETXATTR_H
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETXATTR_H
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
#include "src/__support/OSUtil/linux/syscall.h"
#include "src/__support/common.h"
#include "src/__support/error_or.h"
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/lgetxattr.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/lgetxattr.h
index 1975732642df4..fec3700c4b387 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/lgetxattr.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/lgetxattr.h
@@ -14,6 +14,8 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LGETXATTR_H
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LGETXATTR_H
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
#include "src/__support/OSUtil/linux/syscall.h"
#include "src/__support/common.h"
#include "src/__support/error_or.h"
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/lsetxattr.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/lsetxattr.h
index 2eb2663cbd3ec..776a806986403 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/lsetxattr.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/lsetxattr.h
@@ -14,6 +14,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LSETXATTR_H
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_LSETXATTR_H
+#include "hdr/types/size_t.h"
#include "src/__support/OSUtil/linux/syscall.h"
#include "src/__support/common.h"
#include "src/__support/error_or.h"
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/setxattr.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/setxattr.h
index c10a8455fd92b..dda33e6a0e1ae 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/setxattr.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/setxattr.h
@@ -14,6 +14,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETXATTR_H
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SETXATTR_H
+#include "hdr/types/size_t.h"
#include "src/__support/OSUtil/linux/syscall.h"
#include "src/__support/common.h"
#include "src/__support/error_or.h"
diff --git a/libc/src/sys/xattr/fgetxattr.h b/libc/src/sys/xattr/fgetxattr.h
index 68f24e1af28f0..0f94a5355cbf5 100644
--- a/libc/src/sys/xattr/fgetxattr.h
+++ b/libc/src/sys/xattr/fgetxattr.h
@@ -11,8 +11,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_FGETXATTR_H
-#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_FGETXATTR_H
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_FGETXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_FGETXATTR_H
#include "hdr/types/size_t.h"
#include "hdr/types/ssize_t.h"
@@ -24,4 +24,4 @@ ssize_t fgetxattr(int fd, const char *name, void *value, size_t size);
} // namespace LIBC_NAMESPACE_DECL
-#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_FGETXATTR_H
+#endif // LLVM_LIBC_SRC_SYS_XATTR_FGETXATTR_H
diff --git a/libc/src/sys/xattr/flistxattr.h b/libc/src/sys/xattr/flistxattr.h
index 6493a413fc447..e27fc6814c528 100644
--- a/libc/src/sys/xattr/flistxattr.h
+++ b/libc/src/sys/xattr/flistxattr.h
@@ -11,8 +11,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_FLISTXATTR_H
-#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_FLISTXATTR_H
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_FLISTXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_FLISTXATTR_H
#include "hdr/types/size_t.h"
#include "hdr/types/ssize_t.h"
@@ -24,4 +24,4 @@ ssize_t flistxattr(int fd, char *list, size_t size);
} // namespace LIBC_NAMESPACE_DECL
-#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_FLISTXATTR_H
+#endif // LLVM_LIBC_SRC_SYS_XATTR_FLISTXATTR_H
diff --git a/libc/src/sys/xattr/fsetxattr.h b/libc/src/sys/xattr/fsetxattr.h
index 75eb85df31f13..70458df410a3c 100644
--- a/libc/src/sys/xattr/fsetxattr.h
+++ b/libc/src/sys/xattr/fsetxattr.h
@@ -11,8 +11,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_FSETXATTR_H
-#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_FSETXATTR_H
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_FSETXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_FSETXATTR_H
#include "hdr/types/size_t.h"
#include "src/__support/macros/config.h"
@@ -24,4 +24,4 @@ int fsetxattr(int fd, const char *name, const void *value, size_t size,
} // namespace LIBC_NAMESPACE_DECL
-#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_FSETXATTR_H
+#endif // LLVM_LIBC_SRC_SYS_XATTR_FSETXATTR_H
diff --git a/libc/src/sys/xattr/getxattr.h b/libc/src/sys/xattr/getxattr.h
index 45668baa4bea2..30f21fabfcf4d 100644
--- a/libc/src/sys/xattr/getxattr.h
+++ b/libc/src/sys/xattr/getxattr.h
@@ -11,8 +11,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_GETXATTR_H
-#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_GETXATTR_H
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_GETXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_GETXATTR_H
#include "hdr/types/size_t.h"
#include "hdr/types/ssize_t.h"
@@ -24,4 +24,4 @@ ssize_t getxattr(const char *path, const char *name, void *value, size_t size);
} // namespace LIBC_NAMESPACE_DECL
-#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_GETXATTR_H
+#endif // LLVM_LIBC_SRC_SYS_XATTR_GETXATTR_H
diff --git a/libc/src/sys/xattr/lgetxattr.h b/libc/src/sys/xattr/lgetxattr.h
index 525dd5c7c1603..efd9670b7fabc 100644
--- a/libc/src/sys/xattr/lgetxattr.h
+++ b/libc/src/sys/xattr/lgetxattr.h
@@ -11,8 +11,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_LGETXATTR_H
-#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_LGETXATTR_H
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_LGETXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_LGETXATTR_H
#include "hdr/types/size_t.h"
#include "hdr/types/ssize_t.h"
@@ -24,4 +24,4 @@ ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size);
} // namespace LIBC_NAMESPACE_DECL
-#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_LGETXATTR_H
+#endif // LLVM_LIBC_SRC_SYS_XATTR_LGETXATTR_H
diff --git a/libc/src/sys/xattr/listxattr.h b/libc/src/sys/xattr/listxattr.h
index 535c8e6ce9186..d66c835860ef4 100644
--- a/libc/src/sys/xattr/listxattr.h
+++ b/libc/src/sys/xattr/listxattr.h
@@ -11,8 +11,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_LISTXATTR_H
-#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_LISTXATTR_H
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_LISTXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_LISTXATTR_H
#include "hdr/types/size_t.h"
#include "hdr/types/ssize_t.h"
@@ -24,4 +24,4 @@ ssize_t listxattr(const char *path, char *list, size_t size);
} // namespace LIBC_NAMESPACE_DECL
-#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_LISTXATTR_H
+#endif // LLVM_LIBC_SRC_SYS_XATTR_LISTXATTR_H
diff --git a/libc/src/sys/xattr/llistxattr.h b/libc/src/sys/xattr/llistxattr.h
index 8dabae04fd93a..d8c207f06999b 100644
--- a/libc/src/sys/xattr/llistxattr.h
+++ b/libc/src/sys/xattr/llistxattr.h
@@ -11,8 +11,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_LLISTXATTR_H
-#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_LLISTXATTR_H
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_LLISTXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_LLISTXATTR_H
#include "hdr/types/size_t.h"
#include "hdr/types/ssize_t.h"
@@ -24,4 +24,4 @@ ssize_t llistxattr(const char *path, char *list, size_t size);
} // namespace LIBC_NAMESPACE_DECL
-#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_LLISTXATTR_H
+#endif // LLVM_LIBC_SRC_SYS_XATTR_LLISTXATTR_H
diff --git a/libc/src/sys/xattr/lsetxattr.h b/libc/src/sys/xattr/lsetxattr.h
index 6e6170bc896de..38902fbb22d45 100644
--- a/libc/src/sys/xattr/lsetxattr.h
+++ b/libc/src/sys/xattr/lsetxattr.h
@@ -11,8 +11,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_LSETXATTR_H
-#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_LSETXATTR_H
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_LSETXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_LSETXATTR_H
#include "hdr/types/size_t.h"
#include "src/__support/macros/config.h"
@@ -24,4 +24,4 @@ int lsetxattr(const char *path, const char *name, const void *value,
} // namespace LIBC_NAMESPACE_DECL
-#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_LSETXATTR_H
+#endif // LLVM_LIBC_SRC_SYS_XATTR_LSETXATTR_H
diff --git a/libc/src/sys/xattr/setxattr.h b/libc/src/sys/xattr/setxattr.h
index 87e1bfe5f2d14..c615ebca25231 100644
--- a/libc/src/sys/xattr/setxattr.h
+++ b/libc/src/sys/xattr/setxattr.h
@@ -11,8 +11,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBC_SRC_SYS_XATTR_LINUX_SETXATTR_H
-#define LLVM_LIBC_SRC_SYS_XATTR_LINUX_SETXATTR_H
+#ifndef LLVM_LIBC_SRC_SYS_XATTR_SETXATTR_H
+#define LLVM_LIBC_SRC_SYS_XATTR_SETXATTR_H
#include "hdr/types/size_t.h"
#include "src/__support/macros/config.h"
@@ -24,4 +24,4 @@ int setxattr(const char *path, const char *name, const void *value, size_t size,
} // namespace LIBC_NAMESPACE_DECL
-#endif // LLVM_LIBC_SRC_SYS_XATTR_LINUX_SETXATTR_H
+#endif // LLVM_LIBC_SRC_SYS_XATTR_SETXATTR_H
diff --git a/libc/test/src/sys/xattr/CMakeLists.txt b/libc/test/src/sys/xattr/CMakeLists.txt
index 80adc0ec66268..e856de637c735 100644
--- a/libc/test/src/sys/xattr/CMakeLists.txt
+++ b/libc/test/src/sys/xattr/CMakeLists.txt
@@ -10,6 +10,7 @@ add_libc_test(
libc.hdr.sys_stat_macros
libc.include.sys_xattr
libc.src.__support.CPP.scope
+ libc.src.__support.CPP.string_view
libc.src.__support.OSUtil.osutil
libc.src.__support.libc_errno
libc.src.errno.errno
@@ -31,6 +32,7 @@ add_libc_test(
libc.hdr.sys_stat_macros
libc.include.sys_xattr
libc.src.__support.CPP.scope
+ libc.src.__support.CPP.string_view
libc.src.__support.OSUtil.osutil
libc.src.__support.libc_errno
libc.src.errno.errno
@@ -53,6 +55,7 @@ add_libc_test(
libc.hdr.sys_stat_macros
libc.include.sys_xattr
libc.src.__support.CPP.scope
+ libc.src.__support.CPP.string_view
libc.src.__support.OSUtil.osutil
libc.src.__support.libc_errno
libc.src.errno.errno
@@ -75,6 +78,7 @@ add_libc_test(
libc.hdr.sys_stat_macros
libc.include.sys_xattr
libc.src.__support.CPP.scope
+ libc.src.__support.CPP.string_view
libc.src.__support.OSUtil.osutil
libc.src.__support.libc_errno
libc.src.errno.errno
@@ -98,6 +102,7 @@ add_libc_test(
libc.hdr.types.ssize_t
libc.include.sys_xattr
libc.src.__support.CPP.scope
+ libc.src.__support.CPP.string_view
libc.src.__support.OSUtil.osutil
libc.src.__support.libc_errno
libc.src.errno.errno
@@ -122,6 +127,7 @@ add_libc_test(
libc.hdr.types.ssize_t
libc.include.sys_xattr
libc.src.__support.CPP.scope
+ libc.src.__support.CPP.string_view
libc.src.__support.OSUtil.osutil
libc.src.__support.libc_errno
libc.src.errno.errno
@@ -144,6 +150,7 @@ add_libc_test(
libc.hdr.sys_xattr_macros
libc.include.sys_xattr
libc.src.__support.CPP.scope
+ libc.src.__support.CPP.string_view
libc.src.__support.OSUtil.osutil
libc.src.__support.libc_errno
libc.src.errno.errno
diff --git a/libc/test/src/sys/xattr/fgetxattr_test.cpp b/libc/test/src/sys/xattr/fgetxattr_test.cpp
index a4fde52fb8634..6bf25f6c566af 100644
--- a/libc/test/src/sys/xattr/fgetxattr_test.cpp
+++ b/libc/test/src/sys/xattr/fgetxattr_test.cpp
@@ -13,6 +13,7 @@
#include "hdr/sys_stat_macros.h"
#include "src/__support/CPP/scope.h"
+#include "src/__support/CPP/string_view.h"
#include "src/__support/OSUtil/linux/syscall.h"
#include "src/__support/libc_errno.h"
#include "src/fcntl/creat.h"
@@ -89,6 +90,8 @@ TEST_F(LlvmLibcFgetxattrTest, WithUserExtendedAttribute) {
#if defined(LIBC_ADD_NULL_CHECKS)
TEST_F(LlvmLibcFgetxattrTest, CrashOnNullAttributeName) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fgetxattr_null_attribute.txt");
int fd = recreate_test_file(TEST_FILE_NAME);
ASSERT_ERRNO_SUCCESS();
scope_exit cleanup([&] {
@@ -106,6 +109,8 @@ TEST_F(LlvmLibcFgetxattrTest, CrashOnNullAttributeName) {
}
TEST_F(LlvmLibcFgetxattrTest, CrashOnNullBufferNonZeroSize) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fgetxattr_null_buffer.txt");
int fd = recreate_test_file(TEST_FILE_NAME);
ASSERT_ERRNO_SUCCESS();
scope_exit cleanup([&] {
diff --git a/libc/test/src/sys/xattr/fsetxattr_test.cpp b/libc/test/src/sys/xattr/fsetxattr_test.cpp
index 436042c7f2605..3e6477d6d0281 100644
--- a/libc/test/src/sys/xattr/fsetxattr_test.cpp
+++ b/libc/test/src/sys/xattr/fsetxattr_test.cpp
@@ -15,6 +15,7 @@
#include "hdr/sys_xattr_macros.h"
#include "hdr/types/ssize_t.h"
#include "src/__support/CPP/scope.h"
+#include "src/__support/CPP/string_view.h"
#include "src/__support/OSUtil/linux/syscall.h"
#include "src/__support/libc_errno.h"
#include "src/fcntl/creat.h"
@@ -124,6 +125,8 @@ TEST_F(LlvmLibcFsetxattrTest, SetAttributeWithNonzeroFlags) {
#if defined(LIBC_ADD_NULL_CHECKS)
TEST_F(LlvmLibcFsetxattrTest, CrashOnNullAttributeName) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fsetxattr_null_attribute.txt");
int fd = recreate_test_file(TEST_FILE_NAME);
ASSERT_ERRNO_SUCCESS();
scope_exit cleanup([&] {
@@ -135,12 +138,15 @@ TEST_F(LlvmLibcFsetxattrTest, CrashOnNullAttributeName) {
[fd] {
constexpr size_t BUFFER_SIZE = 32;
char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::fsetxattr(fd, nullptr, buffer, BUFFER_SIZE);
+ LIBC_NAMESPACE::fsetxattr(fd, nullptr, buffer, BUFFER_SIZE,
+ /* flags = */ 0);
},
WITH_SIGNAL(-1));
}
TEST_F(LlvmLibcFsetxattrTest, CrashOnNullBufferNonZeroSize) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fsetxattr_null_buffer.txt");
int fd = recreate_test_file(TEST_FILE_NAME);
ASSERT_ERRNO_SUCCESS();
scope_exit cleanup([&] {
@@ -149,7 +155,10 @@ TEST_F(LlvmLibcFsetxattrTest, CrashOnNullBufferNonZeroSize) {
});
EXPECT_DEATH(
- [fd] { LIBC_NAMESPACE::fsetxattr(fd, "user.attr", nullptr, 32); },
+ [fd] {
+ LIBC_NAMESPACE::fsetxattr(fd, "user.attr", nullptr, 32,
+ /* flags = */ 0);
+ },
WITH_SIGNAL(-1));
}
diff --git a/libc/test/src/sys/xattr/getxattr_test.cpp b/libc/test/src/sys/xattr/getxattr_test.cpp
index 73df59d85e30b..005298e1358fe 100644
--- a/libc/test/src/sys/xattr/getxattr_test.cpp
+++ b/libc/test/src/sys/xattr/getxattr_test.cpp
@@ -13,6 +13,7 @@
#include "hdr/sys_stat_macros.h"
#include "src/__support/CPP/scope.h"
+#include "src/__support/CPP/string_view.h"
#include "src/__support/OSUtil/linux/syscall.h"
#include "src/__support/libc_errno.h"
#include "src/fcntl/creat.h"
@@ -53,13 +54,15 @@ TEST_F(LlvmLibcGetxattrTest, WithUserExtendedAttribute) {
int fd = recreate_test_file(TEST_FILE_NAME);
ASSERT_ERRNO_SUCCESS();
+ scope_exit unlink_file([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
ASSERT_THAT(recreate_test_symlink(TEST_SYMLINK_TARGET, TEST_SYMLINK_NAME),
Succeeds(0));
- scope_exit cleanup([&] {
+ scope_exit unlink_symlink([&] {
ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_SYMLINK_NAME), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
});
string_view XATTR_NAME = "user.test_attr";
diff --git a/libc/test/src/sys/xattr/lgetxattr_test.cpp b/libc/test/src/sys/xattr/lgetxattr_test.cpp
index dbddcbe435a24..4e4257c5f432e 100644
--- a/libc/test/src/sys/xattr/lgetxattr_test.cpp
+++ b/libc/test/src/sys/xattr/lgetxattr_test.cpp
@@ -13,6 +13,7 @@
#include "hdr/sys_stat_macros.h"
#include "src/__support/CPP/scope.h"
+#include "src/__support/CPP/string_view.h"
#include "src/__support/OSUtil/linux/syscall.h"
#include "src/__support/libc_errno.h"
#include "src/fcntl/creat.h"
@@ -53,13 +54,15 @@ TEST_F(LlvmLibcLgetxattrTest, WithUserExtendedAttribute) {
int fd = recreate_test_file(TEST_FILE_NAME);
ASSERT_ERRNO_SUCCESS();
+ scope_exit unlink_file([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
ASSERT_THAT(recreate_test_symlink(TEST_SYMLINK_TARGET, TEST_SYMLINK_NAME),
Succeeds(0));
- scope_exit cleanup([&] {
+ scope_exit unlink_symlink([&] {
ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_SYMLINK_NAME), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
});
string_view XATTR_NAME = "user.test_attr";
diff --git a/libc/test/src/sys/xattr/lsetxattr_test.cpp b/libc/test/src/sys/xattr/lsetxattr_test.cpp
index 57f95ba75cab5..8edc6b4c70fe0 100644
--- a/libc/test/src/sys/xattr/lsetxattr_test.cpp
+++ b/libc/test/src/sys/xattr/lsetxattr_test.cpp
@@ -15,6 +15,7 @@
#include "hdr/sys_xattr_macros.h"
#include "hdr/types/ssize_t.h"
#include "src/__support/CPP/scope.h"
+#include "src/__support/CPP/string_view.h"
#include "src/__support/OSUtil/linux/syscall.h"
#include "src/__support/libc_errno.h"
#include "src/fcntl/creat.h"
@@ -44,11 +45,11 @@ TEST_F(LlvmLibcLsetxattrTest, SetAttributeDefaultFlags) {
libc_make_test_file_path("testdata/lsetxattr_default_flags.txt");
int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
scope_exit cleanup([&] {
ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
});
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
// Set an attribute through the test file name.
{
@@ -82,6 +83,9 @@ TEST_F(LlvmLibcLsetxattrTest, SetAttributeWithNonzeroFlags) {
libc_make_test_file_path("testdata/lsetxattr_nonzero_flags.txt");
int fd = recreate_test_file(TEST_FILE_NAME);
ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
string_view XATTR_NAME = "user.test_attr";
@@ -134,7 +138,8 @@ TEST_F(LlvmLibcLsetxattrTest, CrashOnNullPath) {
[] {
constexpr size_t BUFFER_SIZE = 32;
char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::lsetxattr(nullptr, "user.attr", buffer, BUFFER_SIZE);
+ LIBC_NAMESPACE::lsetxattr(nullptr, "user.attr", buffer, BUFFER_SIZE,
+ /* flags = */ 0);
},
WITH_SIGNAL(-1));
}
@@ -145,7 +150,7 @@ TEST_F(LlvmLibcLsetxattrTest, CrashOnNullAttributeName) {
constexpr size_t BUFFER_SIZE = 32;
char buffer[BUFFER_SIZE] = {};
LIBC_NAMESPACE::lsetxattr("testdata/file.txt", nullptr, buffer,
- BUFFER_SIZE);
+ BUFFER_SIZE, /* flags = */ 0);
},
WITH_SIGNAL(-1));
}
@@ -153,8 +158,8 @@ TEST_F(LlvmLibcLsetxattrTest, CrashOnNullAttributeName) {
TEST_F(LlvmLibcLsetxattrTest, CrashOnNullBufferNonZeroSize) {
EXPECT_DEATH(
[] {
- LIBC_NAMESPACE::lsetxattr("testdata/file.txt", "user.attr", nullptr,
- 32);
+ LIBC_NAMESPACE::lsetxattr("testdata/file.txt", "user.attr", nullptr, 32,
+ /* flags = */ 0);
},
WITH_SIGNAL(-1));
}
diff --git a/libc/test/src/sys/xattr/setxattr_test.cpp b/libc/test/src/sys/xattr/setxattr_test.cpp
index c8a0cbe428baa..ab402fe0b40dc 100644
--- a/libc/test/src/sys/xattr/setxattr_test.cpp
+++ b/libc/test/src/sys/xattr/setxattr_test.cpp
@@ -15,6 +15,7 @@
#include "hdr/sys_xattr_macros.h"
#include "hdr/types/ssize_t.h"
#include "src/__support/CPP/scope.h"
+#include "src/__support/CPP/string_view.h"
#include "src/__support/OSUtil/linux/syscall.h"
#include "src/__support/libc_errno.h"
#include "src/fcntl/creat.h"
@@ -55,13 +56,15 @@ TEST_F(LlvmLibcSetxattrTest, SetAttributeDefaultFlags) {
int fd = recreate_test_file(TEST_FILE_NAME);
ASSERT_ERRNO_SUCCESS();
+ scope_exit unlink_file([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
ASSERT_THAT(recreate_test_symlink(TEST_SYMLINK_TARGET, TEST_SYMLINK_NAME),
Succeeds(0));
- scope_exit cleanup([&] {
+ scope_exit unlink_symlink([&] {
ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_SYMLINK_NAME), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
});
// Set an attribute through the test file name.
@@ -111,6 +114,9 @@ TEST_F(LlvmLibcSetxattrTest, SetAttributeWithNonzeroFlags) {
libc_make_test_file_path("testdata/setxattr_nonzero_flags.txt");
int fd = recreate_test_file(TEST_FILE_NAME);
ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
string_view XATTR_NAME = "user.test_attr";
@@ -163,7 +169,8 @@ TEST_F(LlvmLibcSetxattrTest, CrashOnNullPath) {
[] {
constexpr size_t BUFFER_SIZE = 32;
char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::setxattr(nullptr, "user.attr", buffer, BUFFER_SIZE);
+ LIBC_NAMESPACE::setxattr(nullptr, "user.attr", buffer, BUFFER_SIZE,
+ /* flags = */ 0);
},
WITH_SIGNAL(-1));
}
@@ -174,7 +181,7 @@ TEST_F(LlvmLibcSetxattrTest, CrashOnNullAttributeName) {
constexpr size_t BUFFER_SIZE = 32;
char buffer[BUFFER_SIZE] = {};
LIBC_NAMESPACE::setxattr("testdata/file.txt", nullptr, buffer,
- BUFFER_SIZE);
+ BUFFER_SIZE, /* flags = */ 0);
},
WITH_SIGNAL(-1));
}
@@ -182,7 +189,8 @@ TEST_F(LlvmLibcSetxattrTest, CrashOnNullAttributeName) {
TEST_F(LlvmLibcSetxattrTest, CrashOnNullBufferNonZeroSize) {
EXPECT_DEATH(
[] {
- LIBC_NAMESPACE::setxattr("testdata/file.txt", "user.attr", nullptr, 32);
+ LIBC_NAMESPACE::setxattr("testdata/file.txt", "user.attr", nullptr, 32,
+ /* flags = */ 0);
},
WITH_SIGNAL(-1));
}
>From b7ab3ff5fd93b4e3835316f0395ff2f48aae27fc Mon Sep 17 00:00:00 2001
From: Alex Strelnikov <strel at google.com>
Date: Thu, 24 Sep 2026 14:40:34 +0000
Subject: [PATCH 5/6] Consolidate xattr tests into three files.
---
libc/src/sys/xattr/linux/CMakeLists.txt | 1 +
libc/src/sys/xattr/linux/flistxattr.cpp | 4 +
libc/src/sys/xattr/linux/listxattr.cpp | 2 +
libc/src/sys/xattr/linux/llistxattr.cpp | 2 +
libc/test/src/sys/xattr/CMakeLists.txt | 163 +---------
libc/test/src/sys/xattr/fgetxattr_test.cpp | 128 --------
libc/test/src/sys/xattr/flistxattr_test.cpp | 102 ------
libc/test/src/sys/xattr/fsetxattr_test.cpp | 167 ----------
libc/test/src/sys/xattr/fxattr_test.cpp | 273 ++++++++++++++++
libc/test/src/sys/xattr/getxattr_test.cpp | 161 ----------
libc/test/src/sys/xattr/lgetxattr_test.cpp | 151 ---------
libc/test/src/sys/xattr/listxattr_test.cpp | 150 ---------
libc/test/src/sys/xattr/llistxattr_test.cpp | 148 ---------
libc/test/src/sys/xattr/lsetxattr_test.cpp | 169 ----------
libc/test/src/sys/xattr/lxattr_test.cpp | 302 ++++++++++++++++++
libc/test/src/sys/xattr/setxattr_test.cpp | 200 ------------
libc/test/src/sys/xattr/xattr_test.cpp | 336 ++++++++++++++++++++
17 files changed, 937 insertions(+), 1522 deletions(-)
delete mode 100644 libc/test/src/sys/xattr/fgetxattr_test.cpp
delete mode 100644 libc/test/src/sys/xattr/flistxattr_test.cpp
delete mode 100644 libc/test/src/sys/xattr/fsetxattr_test.cpp
create mode 100644 libc/test/src/sys/xattr/fxattr_test.cpp
delete mode 100644 libc/test/src/sys/xattr/getxattr_test.cpp
delete mode 100644 libc/test/src/sys/xattr/lgetxattr_test.cpp
delete mode 100644 libc/test/src/sys/xattr/listxattr_test.cpp
delete mode 100644 libc/test/src/sys/xattr/llistxattr_test.cpp
delete mode 100644 libc/test/src/sys/xattr/lsetxattr_test.cpp
create mode 100644 libc/test/src/sys/xattr/lxattr_test.cpp
delete mode 100644 libc/test/src/sys/xattr/setxattr_test.cpp
create mode 100644 libc/test/src/sys/xattr/xattr_test.cpp
diff --git a/libc/src/sys/xattr/linux/CMakeLists.txt b/libc/src/sys/xattr/linux/CMakeLists.txt
index e9a48a8cc6581..0a946abb24635 100644
--- a/libc/src/sys/xattr/linux/CMakeLists.txt
+++ b/libc/src/sys/xattr/linux/CMakeLists.txt
@@ -99,6 +99,7 @@ add_entrypoint_object(
libc.src.__support.common
libc.src.__support.libc_errno
libc.src.__support.macros.config
+ libc.src.__support.macros.null_check
libc.src.errno.errno
)
diff --git a/libc/src/sys/xattr/linux/flistxattr.cpp b/libc/src/sys/xattr/linux/flistxattr.cpp
index 68119436aa29e..e384074e26383 100644
--- a/libc/src/sys/xattr/linux/flistxattr.cpp
+++ b/libc/src/sys/xattr/linux/flistxattr.cpp
@@ -16,10 +16,14 @@
#include "src/__support/common.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(ssize_t, flistxattr, (int fd, char *list, size_t size)) {
+ if (size != 0)
+ LIBC_CRASH_ON_NULLPTR(list);
+
ErrorOr<ssize_t> ret = linux_syscalls::flistxattr(fd, list, size);
if (!ret) {
libc_errno = ret.error();
diff --git a/libc/src/sys/xattr/linux/listxattr.cpp b/libc/src/sys/xattr/linux/listxattr.cpp
index d0ef1558ce75c..2d269b24e785c 100644
--- a/libc/src/sys/xattr/linux/listxattr.cpp
+++ b/libc/src/sys/xattr/linux/listxattr.cpp
@@ -23,6 +23,8 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(ssize_t, listxattr,
(const char *path, char *list, size_t size)) {
LIBC_CRASH_ON_NULLPTR(path);
+ if (size != 0)
+ LIBC_CRASH_ON_NULLPTR(list);
ErrorOr<ssize_t> ret = linux_syscalls::listxattr(path, list, size);
if (!ret) {
diff --git a/libc/src/sys/xattr/linux/llistxattr.cpp b/libc/src/sys/xattr/linux/llistxattr.cpp
index 12d073f19deac..6170d48f7f6e0 100644
--- a/libc/src/sys/xattr/linux/llistxattr.cpp
+++ b/libc/src/sys/xattr/linux/llistxattr.cpp
@@ -23,6 +23,8 @@ namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(ssize_t, llistxattr,
(const char *path, char *list, size_t size)) {
LIBC_CRASH_ON_NULLPTR(path);
+ if (size != 0)
+ LIBC_CRASH_ON_NULLPTR(list);
ErrorOr<ssize_t> ret = linux_syscalls::llistxattr(path, list, size);
if (!ret) {
diff --git a/libc/test/src/sys/xattr/CMakeLists.txt b/libc/test/src/sys/xattr/CMakeLists.txt
index e856de637c735..43d9956de50c7 100644
--- a/libc/test/src/sys/xattr/CMakeLists.txt
+++ b/libc/test/src/sys/xattr/CMakeLists.txt
@@ -1,89 +1,24 @@
add_custom_target(libc_sys_xattr_unittests)
add_libc_test(
- fgetxattr_test
+ fxattr_test
SUITE
libc_sys_xattr_unittests
SRCS
- fgetxattr_test.cpp
+ fxattr_test.cpp
DEPENDS
libc.hdr.sys_stat_macros
- libc.include.sys_xattr
+ libc.hdr.sys_xattr_macros
+ libc.hdr.types.size_t
+ libc.hdr.types.ssize_t
libc.src.__support.CPP.scope
libc.src.__support.CPP.string_view
- libc.src.__support.OSUtil.osutil
libc.src.__support.libc_errno
libc.src.errno.errno
libc.src.fcntl.creat
libc.src.sys.xattr.fgetxattr
- libc.src.unistd.close
- libc.src.unistd.unlink
- libc.test.UnitTest.ErrnoCheckingTest
- libc.test.UnitTest.ErrnoSetterMatcher
-)
-
-add_libc_test(
- getxattr_test
- SUITE
- libc_sys_xattr_unittests
- SRCS
- getxattr_test.cpp
- DEPENDS
- libc.hdr.sys_stat_macros
- libc.include.sys_xattr
- libc.src.__support.CPP.scope
- libc.src.__support.CPP.string_view
- libc.src.__support.OSUtil.osutil
- libc.src.__support.libc_errno
- libc.src.errno.errno
- libc.src.fcntl.creat
- libc.src.sys.xattr.getxattr
- libc.src.unistd.close
- libc.src.unistd.symlink
- libc.src.unistd.unlink
- libc.test.UnitTest.ErrnoCheckingTest
- libc.test.UnitTest.ErrnoSetterMatcher
-)
-
-add_libc_test(
- lgetxattr_test
- SUITE
- libc_sys_xattr_unittests
- SRCS
- lgetxattr_test.cpp
- DEPENDS
- libc.hdr.sys_stat_macros
- libc.include.sys_xattr
- libc.src.__support.CPP.scope
- libc.src.__support.CPP.string_view
- libc.src.__support.OSUtil.osutil
- libc.src.__support.libc_errno
- libc.src.errno.errno
- libc.src.fcntl.creat
- libc.src.sys.xattr.lgetxattr
- libc.src.unistd.close
- libc.src.unistd.symlink
- libc.src.unistd.unlink
- libc.test.UnitTest.ErrnoCheckingTest
- libc.test.UnitTest.ErrnoSetterMatcher
-)
-
-add_libc_test(
- flistxattr_test
- SUITE
- libc_sys_xattr_unittests
- SRCS
- flistxattr_test.cpp
- DEPENDS
- libc.hdr.sys_stat_macros
- libc.include.sys_xattr
- libc.src.__support.CPP.scope
- libc.src.__support.CPP.string_view
- libc.src.__support.OSUtil.osutil
- libc.src.__support.libc_errno
- libc.src.errno.errno
- libc.src.fcntl.creat
libc.src.sys.xattr.flistxattr
+ libc.src.sys.xattr.fsetxattr
libc.src.unistd.close
libc.src.unistd.unlink
libc.test.UnitTest.ErrnoCheckingTest
@@ -91,23 +26,24 @@ add_libc_test(
)
add_libc_test(
- setxattr_test
+ lxattr_test
SUITE
libc_sys_xattr_unittests
SRCS
- setxattr_test.cpp
+ lxattr_test.cpp
DEPENDS
libc.hdr.sys_stat_macros
libc.hdr.sys_xattr_macros
+ libc.hdr.types.size_t
libc.hdr.types.ssize_t
- libc.include.sys_xattr
libc.src.__support.CPP.scope
libc.src.__support.CPP.string_view
- libc.src.__support.OSUtil.osutil
libc.src.__support.libc_errno
libc.src.errno.errno
libc.src.fcntl.creat
- libc.src.sys.xattr.setxattr
+ libc.src.sys.xattr.lgetxattr
+ libc.src.sys.xattr.llistxattr
+ libc.src.sys.xattr.lsetxattr
libc.src.unistd.close
libc.src.unistd.symlink
libc.src.unistd.unlink
@@ -116,89 +52,24 @@ add_libc_test(
)
add_libc_test(
- lsetxattr_test
+ xattr_test
SUITE
libc_sys_xattr_unittests
SRCS
- lsetxattr_test.cpp
+ xattr_test.cpp
DEPENDS
libc.hdr.sys_stat_macros
libc.hdr.sys_xattr_macros
+ libc.hdr.types.size_t
libc.hdr.types.ssize_t
- libc.include.sys_xattr
- libc.src.__support.CPP.scope
- libc.src.__support.CPP.string_view
- libc.src.__support.OSUtil.osutil
- libc.src.__support.libc_errno
- libc.src.errno.errno
- libc.src.fcntl.creat
- libc.src.sys.xattr.lsetxattr
- libc.src.unistd.close
- libc.src.unistd.unlink
- libc.test.UnitTest.ErrnoCheckingTest
- libc.test.UnitTest.ErrnoSetterMatcher
-)
-
-add_libc_test(
- fsetxattr_test
- SUITE
- libc_sys_xattr_unittests
- SRCS
- fsetxattr_test.cpp
- DEPENDS
- libc.hdr.sys_stat_macros
- libc.hdr.sys_xattr_macros
- libc.include.sys_xattr
libc.src.__support.CPP.scope
libc.src.__support.CPP.string_view
- libc.src.__support.OSUtil.osutil
- libc.src.__support.libc_errno
- libc.src.errno.errno
- libc.src.fcntl.creat
- libc.src.sys.xattr.fsetxattr
- libc.src.unistd.close
- libc.src.unistd.unlink
- libc.test.UnitTest.ErrnoCheckingTest
- libc.test.UnitTest.ErrnoSetterMatcher
-)
-
-add_libc_test(
- listxattr_test
- SUITE
- libc_sys_xattr_unittests
- SRCS
- listxattr_test.cpp
- DEPENDS
- libc.hdr.sys_stat_macros
- libc.include.sys_xattr
- libc.src.__support.CPP.scope
- libc.src.__support.OSUtil.osutil
libc.src.__support.libc_errno
libc.src.errno.errno
libc.src.fcntl.creat
+ libc.src.sys.xattr.getxattr
libc.src.sys.xattr.listxattr
- libc.src.unistd.close
- libc.src.unistd.symlink
- libc.src.unistd.unlink
- libc.test.UnitTest.ErrnoCheckingTest
- libc.test.UnitTest.ErrnoSetterMatcher
-)
-
-add_libc_test(
- llistxattr_test
- SUITE
- libc_sys_xattr_unittests
- SRCS
- llistxattr_test.cpp
- DEPENDS
- libc.hdr.sys_stat_macros
- libc.include.sys_xattr
- libc.src.__support.CPP.scope
- libc.src.__support.OSUtil.osutil
- libc.src.__support.libc_errno
- libc.src.errno.errno
- libc.src.fcntl.creat
- libc.src.sys.xattr.llistxattr
+ libc.src.sys.xattr.setxattr
libc.src.unistd.close
libc.src.unistd.symlink
libc.src.unistd.unlink
diff --git a/libc/test/src/sys/xattr/fgetxattr_test.cpp b/libc/test/src/sys/xattr/fgetxattr_test.cpp
deleted file mode 100644
index 6bf25f6c566af..0000000000000
--- a/libc/test/src/sys/xattr/fgetxattr_test.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Unit tests for fgetxattr.
-///
-//===----------------------------------------------------------------------===//
-
-#include "hdr/sys_stat_macros.h"
-#include "src/__support/CPP/scope.h"
-#include "src/__support/CPP/string_view.h"
-#include "src/__support/OSUtil/linux/syscall.h"
-#include "src/__support/libc_errno.h"
-#include "src/fcntl/creat.h"
-#include "src/sys/xattr/fgetxattr.h"
-#include "src/unistd/close.h"
-#include "src/unistd/unlink.h"
-#include "test/UnitTest/ErrnoCheckingTest.h"
-#include "test/UnitTest/ErrnoSetterMatcher.h"
-#include "test/UnitTest/Test.h"
-#include <sys/syscall.h>
-
-namespace {
-
-using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
-using LlvmLibcFgetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
-using LIBC_NAMESPACE::cpp::scope_exit;
-using LIBC_NAMESPACE::cpp::string_view;
-
-int recreate_test_file(const char *path) {
- LIBC_NAMESPACE::unlink(path);
- LIBC_NAMESPACE::libc_errno = 0;
- return LIBC_NAMESPACE::creat(path, S_IRWXU);
-}
-
-TEST_F(LlvmLibcFgetxattrTest, WithUserExtendedAttribute) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/fgetxattr.txt");
-
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
-
- string_view XATTR_NAME = "user.test_attr";
- string_view XATTR_VALUE = "test_value";
- ASSERT_EQ(0, LIBC_NAMESPACE::syscall_impl<int>(
- SYS_setxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), XATTR_VALUE.data(), XATTR_VALUE.size(),
- /* flags = */ 0));
-
- EXPECT_THAT(LIBC_NAMESPACE::fgetxattr(fd, XATTR_NAME.data(), nullptr, 0),
- Succeeds<ssize_t>(XATTR_VALUE.size()));
-
- {
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
-
- char buffer[BUFFER_SIZE] = {};
- ASSERT_THAT(
- LIBC_NAMESPACE::fgetxattr(fd, XATTR_NAME.data(), buffer, BUFFER_SIZE),
- Succeeds(XATTR_VALUE.size()));
- string_view result_str(buffer, XATTR_VALUE.size());
- EXPECT_EQ(result_str, XATTR_VALUE);
- }
-
- // Call with insufficient buffer size and missing attribute to check failing
- // errno.
- {
- constexpr size_t BUFFER_SIZE = 8;
- ASSERT_LT(BUFFER_SIZE, XATTR_VALUE.size());
-
- char buffer[BUFFER_SIZE] = {};
- EXPECT_THAT(
- LIBC_NAMESPACE::fgetxattr(fd, XATTR_NAME.data(), buffer, BUFFER_SIZE),
- Fails<ssize_t>(ERANGE));
- EXPECT_THAT(LIBC_NAMESPACE::fgetxattr(fd, "user.missing_test_attr", buffer,
- BUFFER_SIZE),
- Fails<ssize_t>(ENODATA));
- }
-}
-
-#if defined(LIBC_ADD_NULL_CHECKS)
-
-TEST_F(LlvmLibcFgetxattrTest, CrashOnNullAttributeName) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/fgetxattr_null_attribute.txt");
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
-
- EXPECT_DEATH(
- [fd] {
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::fgetxattr(fd, nullptr, buffer, BUFFER_SIZE);
- },
- WITH_SIGNAL(-1));
-}
-
-TEST_F(LlvmLibcFgetxattrTest, CrashOnNullBufferNonZeroSize) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/fgetxattr_null_buffer.txt");
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
-
- EXPECT_DEATH(
- [fd] { LIBC_NAMESPACE::fgetxattr(fd, "user.attr", nullptr, 32); },
- WITH_SIGNAL(-1));
-}
-
-#endif // LIBC_ADD_NULL_CHECKS
-
-} // namespace
diff --git a/libc/test/src/sys/xattr/flistxattr_test.cpp b/libc/test/src/sys/xattr/flistxattr_test.cpp
deleted file mode 100644
index 474d0ae81d559..0000000000000
--- a/libc/test/src/sys/xattr/flistxattr_test.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Unit tests for flistxattr.
-///
-//===----------------------------------------------------------------------===//
-
-#include "hdr/sys_stat_macros.h"
-#include "src/__support/CPP/scope.h"
-#include "src/__support/OSUtil/linux/syscall.h"
-#include "src/__support/libc_errno.h"
-#include "src/fcntl/creat.h"
-#include "src/sys/xattr/flistxattr.h"
-#include "src/unistd/close.h"
-#include "src/unistd/unlink.h"
-#include "test/UnitTest/ErrnoCheckingTest.h"
-#include "test/UnitTest/ErrnoSetterMatcher.h"
-#include "test/UnitTest/Test.h"
-#include <sys/syscall.h>
-
-namespace {
-
-using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
-using LlvmLibcListxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
-using LIBC_NAMESPACE::cpp::scope_exit;
-using LIBC_NAMESPACE::cpp::string_view;
-
-int recreate_test_file(const char *path) {
- LIBC_NAMESPACE::unlink(path);
- LIBC_NAMESPACE::libc_errno = 0;
- return LIBC_NAMESPACE::creat(path, S_IRWXU);
-}
-
-TEST_F(LlvmLibcListxattrTest, NoExtendedAttributes) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/flistxattr_no_xattrs.txt");
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
-
- EXPECT_THAT(LIBC_NAMESPACE::flistxattr(fd, nullptr, 0), Succeeds<ssize_t>(0));
-
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- EXPECT_THAT(LIBC_NAMESPACE::flistxattr(fd, buffer, BUFFER_SIZE),
- Succeeds<ssize_t>(0));
-}
-
-TEST_F(LlvmLibcListxattrTest, WithUserExtendedAttribute) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/flistxattr_with_user_xattr.txt");
-
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
-
- string_view XATTR_NAME = "user.test_attr";
- string_view XATTR_VALUE = "test_value";
- ASSERT_EQ(0, LIBC_NAMESPACE::syscall_impl<int>(
- SYS_fsetxattr, fd, XATTR_NAME.data(), XATTR_VALUE.data(),
- XATTR_VALUE.size(),
- /* flags = */ 0));
- size_t xattr_name_null_terminated_len = XATTR_NAME.size() + 1;
-
- ASSERT_THAT(LIBC_NAMESPACE::flistxattr(fd, nullptr, 0),
- Succeeds<ssize_t>(xattr_name_null_terminated_len));
-
- {
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, xattr_name_null_terminated_len);
-
- char buffer[BUFFER_SIZE] = {};
- ASSERT_THAT(LIBC_NAMESPACE::flistxattr(fd, buffer, BUFFER_SIZE),
- Succeeds(xattr_name_null_terminated_len));
- string_view result_str(buffer, xattr_name_null_terminated_len - 1);
- EXPECT_EQ(result_str, XATTR_NAME);
- }
-
- // Call with insufficient buffer size to check failing errno.
- {
- constexpr size_t BUFFER_SIZE = 14;
- ASSERT_LT(BUFFER_SIZE, xattr_name_null_terminated_len);
-
- char buffer[BUFFER_SIZE] = {};
- EXPECT_THAT(LIBC_NAMESPACE::flistxattr(fd, buffer, BUFFER_SIZE),
- Fails<ssize_t>(ERANGE));
- }
-}
-
-} // namespace
diff --git a/libc/test/src/sys/xattr/fsetxattr_test.cpp b/libc/test/src/sys/xattr/fsetxattr_test.cpp
deleted file mode 100644
index 3e6477d6d0281..0000000000000
--- a/libc/test/src/sys/xattr/fsetxattr_test.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Unit tests for fsetxattr.
-///
-//===----------------------------------------------------------------------===//
-
-#include "hdr/sys_stat_macros.h"
-#include "hdr/sys_xattr_macros.h"
-#include "hdr/types/ssize_t.h"
-#include "src/__support/CPP/scope.h"
-#include "src/__support/CPP/string_view.h"
-#include "src/__support/OSUtil/linux/syscall.h"
-#include "src/__support/libc_errno.h"
-#include "src/fcntl/creat.h"
-#include "src/sys/xattr/fsetxattr.h"
-#include "src/unistd/close.h"
-#include "src/unistd/unlink.h"
-#include "test/UnitTest/ErrnoCheckingTest.h"
-#include "test/UnitTest/ErrnoSetterMatcher.h"
-#include "test/UnitTest/Test.h"
-#include <sys/syscall.h>
-
-namespace {
-
-using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
-using LlvmLibcFsetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
-using LIBC_NAMESPACE::cpp::scope_exit;
-using LIBC_NAMESPACE::cpp::string_view;
-
-int recreate_test_file(const char *path) {
- LIBC_NAMESPACE::unlink(path);
- LIBC_NAMESPACE::libc_errno = 0;
- return LIBC_NAMESPACE::creat(path, S_IRWXU);
-}
-
-TEST_F(LlvmLibcFsetxattrTest, SetAttributeDefaultFlags) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/fsetxattr_default_flags.txt");
-
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
-
- string_view XATTR_NAME = "user.test_attr";
- string_view XATTR_VALUE = "test_value";
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
- char buffer[BUFFER_SIZE] = {};
-
- ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
- XATTR_VALUE.data(), XATTR_VALUE.size(),
- /* flags = */ 0),
- Succeeds(0));
-
- ASSERT_EQ(static_cast<ssize_t>(XATTR_VALUE.size()),
- LIBC_NAMESPACE::syscall_impl<ssize_t>(
- SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), buffer, BUFFER_SIZE));
- EXPECT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
-}
-
-TEST_F(LlvmLibcFsetxattrTest, SetAttributeWithNonzeroFlags) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/fsetxattr_nonzero_flags.txt");
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
-
- string_view XATTR_NAME = "user.test_attr";
- string_view XATTR_VALUE = "test_value";
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
- char buffer[BUFFER_SIZE] = {};
-
- // Try replace-only before attribute exists.
- ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
- XATTR_VALUE.data(), XATTR_VALUE.size(),
- XATTR_REPLACE),
- Fails(ENODATA));
-
- ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
- XATTR_VALUE.data(), XATTR_VALUE.size(),
- /* flags = */ XATTR_CREATE),
- Succeeds(0));
-
- ASSERT_EQ(static_cast<ssize_t>(XATTR_VALUE.size()),
- LIBC_NAMESPACE::syscall_impl<ssize_t>(
- SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), buffer, BUFFER_SIZE));
- ASSERT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
-
- // Replace-only now that the attribute exists.
- string_view NEW_XATTR_VALUE = "new_test_value";
- ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
- NEW_XATTR_VALUE.data(),
- NEW_XATTR_VALUE.size(), XATTR_REPLACE),
- Succeeds(0));
-
- ASSERT_EQ(static_cast<ssize_t>(NEW_XATTR_VALUE.size()),
- LIBC_NAMESPACE::syscall_impl<ssize_t>(
- SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), buffer, BUFFER_SIZE));
- ASSERT_EQ(string_view(buffer, NEW_XATTR_VALUE.size()), NEW_XATTR_VALUE);
-
- // Try create-only when the attribute already exists.
- ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
- XATTR_VALUE.data(), XATTR_VALUE.size(),
- XATTR_CREATE),
- Fails(EEXIST));
-}
-
-#if defined(LIBC_ADD_NULL_CHECKS)
-
-TEST_F(LlvmLibcFsetxattrTest, CrashOnNullAttributeName) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/fsetxattr_null_attribute.txt");
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
-
- EXPECT_DEATH(
- [fd] {
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::fsetxattr(fd, nullptr, buffer, BUFFER_SIZE,
- /* flags = */ 0);
- },
- WITH_SIGNAL(-1));
-}
-
-TEST_F(LlvmLibcFsetxattrTest, CrashOnNullBufferNonZeroSize) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/fsetxattr_null_buffer.txt");
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
-
- EXPECT_DEATH(
- [fd] {
- LIBC_NAMESPACE::fsetxattr(fd, "user.attr", nullptr, 32,
- /* flags = */ 0);
- },
- WITH_SIGNAL(-1));
-}
-
-#endif // LIBC_ADD_NULL_CHECKS
-
-} // namespace
diff --git a/libc/test/src/sys/xattr/fxattr_test.cpp b/libc/test/src/sys/xattr/fxattr_test.cpp
new file mode 100644
index 0000000000000..10200236da5dd
--- /dev/null
+++ b/libc/test/src/sys/xattr/fxattr_test.cpp
@@ -0,0 +1,273 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for fgetxattr, fsetxattr, and, flistxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/sys_stat_macros.h"
+#include "hdr/sys_xattr_macros.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/CPP/scope.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/libc_errno.h"
+#include "src/fcntl/creat.h"
+#include "src/sys/xattr/fgetxattr.h"
+#include "src/sys/xattr/flistxattr.h"
+#include "src/sys/xattr/fsetxattr.h"
+#include "src/unistd/close.h"
+#include "src/unistd/unlink.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+namespace {
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LlvmLibcFxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::cpp::scope_exit;
+using LIBC_NAMESPACE::cpp::string_view;
+
+int recreate_test_file(const char *path) {
+ LIBC_NAMESPACE::unlink(path);
+ LIBC_NAMESPACE::libc_errno = 0;
+ return LIBC_NAMESPACE::creat(path, S_IRWXU);
+}
+
+TEST_F(LlvmLibcFxattrTest, GetAndListWithNoAttributeSet) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fxattr_no_xattrs.txt");
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+
+ EXPECT_THAT(LIBC_NAMESPACE::fgetxattr(fd, "user.missing_test_attr", buffer,
+ BUFFER_SIZE),
+ Fails<ssize_t>(ENODATA));
+
+ EXPECT_THAT(LIBC_NAMESPACE::flistxattr(fd, nullptr, 0), Succeeds<ssize_t>(0));
+ EXPECT_THAT(LIBC_NAMESPACE::flistxattr(fd, buffer, BUFFER_SIZE),
+ Succeeds<ssize_t>(0));
+}
+
+TEST_F(LlvmLibcFxattrTest, SetGetAndListWithUserExtendedAttribute) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fxattr_testfile.txt");
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ string_view XATTR_NAME = "user.test_attr";
+ string_view XATTR_VALUE = "test_value";
+ ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ 0),
+ Succeeds(0));
+ size_t xattr_name_null_terminated_len = XATTR_NAME.size() + 1;
+
+ // Get and list with null and sufficient buffer size.
+ EXPECT_THAT(LIBC_NAMESPACE::fgetxattr(fd, XATTR_NAME.data(), nullptr, 0),
+ Succeeds<ssize_t>(XATTR_VALUE.size()));
+ EXPECT_THAT(LIBC_NAMESPACE::flistxattr(fd, nullptr, 0),
+ Succeeds<ssize_t>(xattr_name_null_terminated_len));
+ {
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_NAME.size());
+
+ char buffer[BUFFER_SIZE] = {};
+ ASSERT_THAT(
+ LIBC_NAMESPACE::fgetxattr(fd, XATTR_NAME.data(), buffer, BUFFER_SIZE),
+ Succeeds(XATTR_VALUE.size()));
+ string_view result_str(buffer, XATTR_VALUE.size());
+ EXPECT_EQ(result_str, XATTR_VALUE);
+ }
+ {
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, xattr_name_null_terminated_len);
+
+ char buffer[BUFFER_SIZE] = {};
+ ASSERT_THAT(LIBC_NAMESPACE::flistxattr(fd, buffer, BUFFER_SIZE),
+ Succeeds(xattr_name_null_terminated_len));
+ string_view result_str(buffer, xattr_name_null_terminated_len - 1);
+ EXPECT_EQ(result_str, XATTR_NAME);
+ }
+
+ // Get and list with insufficient buffer size, and get with missing attribute
+ // to check failing errno.
+ {
+ constexpr size_t BUFFER_SIZE = 8;
+ ASSERT_LT(BUFFER_SIZE, xattr_name_null_terminated_len);
+ ASSERT_LT(BUFFER_SIZE, XATTR_VALUE.size());
+ char buffer[BUFFER_SIZE] = {};
+
+ EXPECT_THAT(
+ LIBC_NAMESPACE::fgetxattr(fd, XATTR_NAME.data(), buffer, BUFFER_SIZE),
+ Fails<ssize_t>(ERANGE));
+
+ EXPECT_THAT(LIBC_NAMESPACE::flistxattr(fd, buffer, BUFFER_SIZE),
+ Fails<ssize_t>(ERANGE));
+
+ EXPECT_THAT(LIBC_NAMESPACE::fgetxattr(fd, "user.missing_test_attr", buffer,
+ BUFFER_SIZE),
+ Fails<ssize_t>(ENODATA));
+ }
+}
+
+TEST_F(LlvmLibcFxattrTest, SetAttributeWithNonzeroFlags) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fxattr_nonzero_flags_testfile.txt");
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ string_view XATTR_NAME = "user.test_attr";
+ string_view XATTR_VALUE = "test_value";
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+ char buffer[BUFFER_SIZE] = {};
+
+ // Try replace-only before attribute exists.
+ ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ XATTR_REPLACE),
+ Fails(ENODATA));
+
+ ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ XATTR_CREATE),
+ Succeeds(0));
+
+ EXPECT_THAT(
+ LIBC_NAMESPACE::fgetxattr(fd, XATTR_NAME.data(), buffer, BUFFER_SIZE),
+ Succeeds<ssize_t>(XATTR_VALUE.size()));
+ ASSERT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
+
+ // Replace-only now that the attribute does exist.
+ string_view NEW_XATTR_VALUE = "new_test_value";
+ ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
+ NEW_XATTR_VALUE.data(),
+ NEW_XATTR_VALUE.size(), XATTR_REPLACE),
+ Succeeds(0));
+
+ EXPECT_THAT(
+ LIBC_NAMESPACE::fgetxattr(fd, XATTR_NAME.data(), buffer, BUFFER_SIZE),
+ Succeeds<ssize_t>(NEW_XATTR_VALUE.size()));
+ ASSERT_EQ(string_view(buffer, NEW_XATTR_VALUE.size()), NEW_XATTR_VALUE);
+
+ // Try create-only when the attribute already exists.
+ ASSERT_THAT(LIBC_NAMESPACE::fsetxattr(fd, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ XATTR_CREATE),
+ Fails(EEXIST));
+}
+
+#if 1 // defined(LIBC_ADD_NULL_CHECKS)
+
+TEST_F(LlvmLibcFxattrTest, SetCrashesOnNullAttributeName) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fsetxattr_null_attribute.txt");
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ EXPECT_DEATH(
+ [fd] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::fsetxattr(fd, nullptr, buffer, BUFFER_SIZE,
+ /* flags = */ 0);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcFxattrTest, SetCrashesOnNullBufferNonZeroSize) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fsetxattr_null_buffer.txt");
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ EXPECT_DEATH(
+ [fd] {
+ LIBC_NAMESPACE::fsetxattr(fd, "user.attr", nullptr, 32,
+ /* flags = */ 0);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcFxattrTest, GetCrashesOnNullAttributeName) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fgetxattr_null_attribute.txt");
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ EXPECT_DEATH(
+ [fd] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::fgetxattr(fd, nullptr, buffer, BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcFxattrTest, GetCrashesOnNullBufferNonZeroSize) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fgetxattr_null_buffer.txt");
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ EXPECT_DEATH(
+ [fd] { LIBC_NAMESPACE::fgetxattr(fd, "user.attr", nullptr, 32); },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcFxattrTest, ListCrashesOnNullBufferNonZeroSize) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/fgetxattr_null_buffer.txt");
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ EXPECT_DEATH([fd] { LIBC_NAMESPACE::flistxattr(fd, nullptr, 32); },
+ WITH_SIGNAL(-1));
+}
+
+#endif // LIBC_ADD_NULL_CHECKS
+
+} // namespace
diff --git a/libc/test/src/sys/xattr/getxattr_test.cpp b/libc/test/src/sys/xattr/getxattr_test.cpp
deleted file mode 100644
index 005298e1358fe..0000000000000
--- a/libc/test/src/sys/xattr/getxattr_test.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Unit tests for getxattr.
-///
-//===----------------------------------------------------------------------===//
-
-#include "hdr/sys_stat_macros.h"
-#include "src/__support/CPP/scope.h"
-#include "src/__support/CPP/string_view.h"
-#include "src/__support/OSUtil/linux/syscall.h"
-#include "src/__support/libc_errno.h"
-#include "src/fcntl/creat.h"
-#include "src/sys/xattr/getxattr.h"
-#include "src/unistd/close.h"
-#include "src/unistd/symlink.h"
-#include "src/unistd/unlink.h"
-#include "test/UnitTest/ErrnoCheckingTest.h"
-#include "test/UnitTest/ErrnoSetterMatcher.h"
-#include "test/UnitTest/Test.h"
-#include <sys/syscall.h>
-
-namespace {
-
-using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
-using LlvmLibcGetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
-using LIBC_NAMESPACE::cpp::scope_exit;
-using LIBC_NAMESPACE::cpp::string_view;
-
-int recreate_test_file(const char *path) {
- LIBC_NAMESPACE::unlink(path);
- LIBC_NAMESPACE::libc_errno = 0;
- return LIBC_NAMESPACE::creat(path, S_IRWXU);
-}
-
-int recreate_test_symlink(const char *target, const char *linkpath) {
- LIBC_NAMESPACE::unlink(linkpath);
- LIBC_NAMESPACE::libc_errno = 0;
- return LIBC_NAMESPACE::symlink(target, linkpath);
-}
-
-TEST_F(LlvmLibcGetxattrTest, WithUserExtendedAttribute) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/getxattr.txt");
- constexpr const char *TEST_SYMLINK_TARGET = "getxattr.txt";
- const LIBC_NAMESPACE::CString TEST_SYMLINK_NAME =
- libc_make_test_file_path("testdata/getxattr_symlink.txt");
-
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- scope_exit unlink_file([&] {
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
-
- ASSERT_THAT(recreate_test_symlink(TEST_SYMLINK_TARGET, TEST_SYMLINK_NAME),
- Succeeds(0));
- scope_exit unlink_symlink([&] {
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_SYMLINK_NAME), Succeeds(0));
- });
-
- string_view XATTR_NAME = "user.test_attr";
- string_view XATTR_VALUE = "test_value";
- ASSERT_EQ(0, LIBC_NAMESPACE::syscall_impl<int>(
- SYS_setxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), XATTR_VALUE.data(), XATTR_VALUE.size(),
- /* flags = */ 0));
-
- // Call with the test file path.
- {
- EXPECT_THAT(
- LIBC_NAMESPACE::getxattr(TEST_FILE_NAME, XATTR_NAME.data(), nullptr, 0),
- Succeeds<ssize_t>(XATTR_VALUE.size()));
-
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
-
- char buffer[BUFFER_SIZE] = {};
- ASSERT_THAT(LIBC_NAMESPACE::getxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- buffer, BUFFER_SIZE),
- Succeeds(XATTR_VALUE.size()));
- string_view result_str(buffer, XATTR_VALUE.size());
- EXPECT_EQ(result_str, XATTR_VALUE);
- }
-
- // Call with the symlink path to verify the correct syscall is used
- // internally; getxattr instead of lgetxattr.
- {
- EXPECT_THAT(LIBC_NAMESPACE::getxattr(TEST_SYMLINK_NAME, XATTR_NAME.data(),
- nullptr, 0),
- Succeeds<ssize_t>(XATTR_VALUE.size()));
-
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
-
- char buffer[BUFFER_SIZE] = {};
- ASSERT_THAT(LIBC_NAMESPACE::getxattr(TEST_SYMLINK_NAME, XATTR_NAME.data(),
- buffer, BUFFER_SIZE),
- Succeeds(XATTR_VALUE.size()));
- string_view result_str(buffer, XATTR_VALUE.size());
- EXPECT_EQ(result_str, XATTR_VALUE);
- }
-
- // Call with insufficient buffer size and missing attribute to check failing
- // errno.
- {
- constexpr size_t BUFFER_SIZE = 8;
- ASSERT_LT(BUFFER_SIZE, XATTR_VALUE.size());
-
- char buffer[BUFFER_SIZE] = {};
-
- EXPECT_THAT(LIBC_NAMESPACE::getxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- buffer, BUFFER_SIZE),
- Fails<ssize_t>(ERANGE));
- EXPECT_THAT(LIBC_NAMESPACE::getxattr(TEST_FILE_NAME,
- "user.missing_test_attr", buffer,
- BUFFER_SIZE),
- Fails<ssize_t>(ENODATA));
- }
-}
-
-#if defined(LIBC_ADD_NULL_CHECKS)
-
-TEST_F(LlvmLibcGetxattrTest, CrashOnNullPath) {
- EXPECT_DEATH(
- [] {
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::getxattr(nullptr, "user.attr", buffer, BUFFER_SIZE);
- },
- WITH_SIGNAL(-1));
-}
-
-TEST_F(LlvmLibcGetxattrTest, CrashOnNullAttributeName) {
- EXPECT_DEATH(
- [] {
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::getxattr("testdata/file.txt", nullptr, buffer,
- BUFFER_SIZE);
- },
- WITH_SIGNAL(-1));
-}
-
-TEST_F(LlvmLibcGetxattrTest, CrashOnNullBufferNonZeroSize) {
- EXPECT_DEATH(
- [] {
- LIBC_NAMESPACE::getxattr("testdata/file.txt", "user.attr", nullptr, 32);
- },
- WITH_SIGNAL(-1));
-}
-
-#endif // LIBC_ADD_NULL_CHECKS
-
-} // namespace
diff --git a/libc/test/src/sys/xattr/lgetxattr_test.cpp b/libc/test/src/sys/xattr/lgetxattr_test.cpp
deleted file mode 100644
index 4e4257c5f432e..0000000000000
--- a/libc/test/src/sys/xattr/lgetxattr_test.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Unit tests for lgetxattr.
-///
-//===----------------------------------------------------------------------===//
-
-#include "hdr/sys_stat_macros.h"
-#include "src/__support/CPP/scope.h"
-#include "src/__support/CPP/string_view.h"
-#include "src/__support/OSUtil/linux/syscall.h"
-#include "src/__support/libc_errno.h"
-#include "src/fcntl/creat.h"
-#include "src/sys/xattr/lgetxattr.h"
-#include "src/unistd/close.h"
-#include "src/unistd/symlink.h"
-#include "src/unistd/unlink.h"
-#include "test/UnitTest/ErrnoCheckingTest.h"
-#include "test/UnitTest/ErrnoSetterMatcher.h"
-#include "test/UnitTest/Test.h"
-#include <sys/syscall.h>
-
-namespace {
-
-using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
-using LlvmLibcLgetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
-using LIBC_NAMESPACE::cpp::scope_exit;
-using LIBC_NAMESPACE::cpp::string_view;
-
-int recreate_test_file(const char *path) {
- LIBC_NAMESPACE::unlink(path);
- LIBC_NAMESPACE::libc_errno = 0;
- return LIBC_NAMESPACE::creat(path, S_IRWXU);
-}
-
-int recreate_test_symlink(const char *target, const char *linkpath) {
- LIBC_NAMESPACE::unlink(linkpath);
- LIBC_NAMESPACE::libc_errno = 0;
- return LIBC_NAMESPACE::symlink(target, linkpath);
-}
-
-TEST_F(LlvmLibcLgetxattrTest, WithUserExtendedAttribute) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/lgetxattr.txt");
- constexpr const char *TEST_SYMLINK_TARGET = "lgetxattr.txt";
- const LIBC_NAMESPACE::CString TEST_SYMLINK_NAME =
- libc_make_test_file_path("testdata/lgetxattr_symlink.txt");
-
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- scope_exit unlink_file([&] {
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
-
- ASSERT_THAT(recreate_test_symlink(TEST_SYMLINK_TARGET, TEST_SYMLINK_NAME),
- Succeeds(0));
- scope_exit unlink_symlink([&] {
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_SYMLINK_NAME), Succeeds(0));
- });
-
- string_view XATTR_NAME = "user.test_attr";
- string_view XATTR_VALUE = "test_value";
- ASSERT_EQ(0, LIBC_NAMESPACE::syscall_impl<int>(
- SYS_setxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), XATTR_VALUE.data(), XATTR_VALUE.size(),
- /* flags = */ 0));
-
- // Call with the test file path.
- {
- EXPECT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- nullptr, 0),
- Succeeds<ssize_t>(XATTR_VALUE.size()));
-
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
-
- char buffer[BUFFER_SIZE] = {};
- ASSERT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- buffer, BUFFER_SIZE),
- Succeeds(XATTR_VALUE.size()));
- string_view result_str(buffer, XATTR_VALUE.size());
- EXPECT_EQ(result_str, XATTR_VALUE);
- }
-
- // Call with the symlink path to verify the correct syscall is used
- // internally; lgetxattr instead of getxattr.
- {
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
-
- char buffer[BUFFER_SIZE] = {};
- EXPECT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_SYMLINK_NAME, XATTR_NAME.data(),
- buffer, BUFFER_SIZE),
- Fails<ssize_t>(ENODATA));
- }
-
- // Call with insufficient buffer size to check failing errno.
- {
- constexpr size_t BUFFER_SIZE = 8;
- ASSERT_LT(BUFFER_SIZE, XATTR_VALUE.size());
-
- char buffer[BUFFER_SIZE] = {};
-
- EXPECT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- buffer, BUFFER_SIZE),
- Fails<ssize_t>(ERANGE));
- }
-}
-
-#if defined(LIBC_ADD_NULL_CHECKS)
-
-TEST_F(LlvmLibcLgetxattrTest, CrashOnNullPath) {
- EXPECT_DEATH(
- [] {
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::lgetxattr(nullptr, "user.attr", buffer, BUFFER_SIZE);
- },
- WITH_SIGNAL(-1));
-}
-
-TEST_F(LlvmLibcLgetxattrTest, CrashOnNullAttributeName) {
- EXPECT_DEATH(
- [] {
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::lgetxattr("testdata/file.txt", nullptr, buffer,
- BUFFER_SIZE);
- },
- WITH_SIGNAL(-1));
-}
-
-TEST_F(LlvmLibcLgetxattrTest, CrashOnNullBufferNonZeroSize) {
- EXPECT_DEATH(
- [] {
- LIBC_NAMESPACE::lgetxattr("testdata/file.txt", "user.attr", nullptr,
- 32);
- },
- WITH_SIGNAL(-1));
-}
-
-#endif // LIBC_ADD_NULL_CHECKS
-
-} // namespace
diff --git a/libc/test/src/sys/xattr/listxattr_test.cpp b/libc/test/src/sys/xattr/listxattr_test.cpp
deleted file mode 100644
index da72fd0602fcf..0000000000000
--- a/libc/test/src/sys/xattr/listxattr_test.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Unit tests for listxattr.
-///
-//===----------------------------------------------------------------------===//
-
-#include "hdr/sys_stat_macros.h"
-#include "src/__support/CPP/scope.h"
-#include "src/__support/OSUtil/linux/syscall.h"
-#include "src/__support/libc_errno.h"
-#include "src/fcntl/creat.h"
-#include "src/sys/xattr/listxattr.h"
-#include "src/unistd/close.h"
-#include "src/unistd/symlink.h"
-#include "src/unistd/unlink.h"
-#include "test/UnitTest/ErrnoCheckingTest.h"
-#include "test/UnitTest/ErrnoSetterMatcher.h"
-#include "test/UnitTest/Test.h"
-#include <sys/syscall.h>
-
-namespace {
-
-using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
-using LlvmLibcListxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
-using LIBC_NAMESPACE::cpp::scope_exit;
-using LIBC_NAMESPACE::cpp::string_view;
-
-int recreate_test_file(const char *path) {
- LIBC_NAMESPACE::unlink(path);
- LIBC_NAMESPACE::libc_errno = 0;
- return LIBC_NAMESPACE::creat(path, S_IRWXU);
-}
-
-int recreate_test_symlink(const char *target, const char *linkpath) {
- LIBC_NAMESPACE::unlink(linkpath);
- LIBC_NAMESPACE::libc_errno = 0;
- return LIBC_NAMESPACE::symlink(target, linkpath);
-}
-
-TEST_F(LlvmLibcListxattrTest, NoExtendedAttributes) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/listxattr_no_xattrs.txt");
-
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
-
- EXPECT_THAT(LIBC_NAMESPACE::listxattr(TEST_FILE_NAME, nullptr, 0),
- Succeeds<ssize_t>(0));
-
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- EXPECT_THAT(LIBC_NAMESPACE::listxattr(TEST_FILE_NAME, buffer, BUFFER_SIZE),
- Succeeds<ssize_t>(0));
-}
-
-TEST_F(LlvmLibcListxattrTest, WithUserExtendedAttribute) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/listxattr_with_user_xattr.txt");
- constexpr const char *TEST_SYMLINK_TARGET = "listxattr_with_user_xattr.txt";
- const LIBC_NAMESPACE::CString TEST_SYMLINK_NAME =
- libc_make_test_file_path("testdata/listxattr_symlink.txt");
-
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
-
- ASSERT_THAT(recreate_test_symlink(TEST_SYMLINK_TARGET, TEST_SYMLINK_NAME),
- Succeeds(0));
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_SYMLINK_NAME), Succeeds(0));
- });
-
- string_view XATTR_NAME = "user.test_attr";
- string_view XATTR_VALUE = "test_value";
- ASSERT_EQ(0, LIBC_NAMESPACE::syscall_impl<int>(
- SYS_setxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), XATTR_VALUE.data(), XATTR_VALUE.size(),
- /* flags = */ 0));
- size_t xattr_name_null_terminated_len = XATTR_NAME.size() + 1;
-
- // Call with the test file path.
- {
- ASSERT_THAT(LIBC_NAMESPACE::listxattr(TEST_FILE_NAME, nullptr, 0),
- Succeeds<ssize_t>(xattr_name_null_terminated_len));
-
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, xattr_name_null_terminated_len);
-
- char buffer[BUFFER_SIZE] = {};
- ASSERT_THAT(LIBC_NAMESPACE::listxattr(TEST_FILE_NAME, buffer, BUFFER_SIZE),
- Succeeds(xattr_name_null_terminated_len));
- string_view result_str(buffer, xattr_name_null_terminated_len - 1);
- EXPECT_EQ(result_str, XATTR_NAME);
- }
-
- // Call with the symlink path to verify the correct syscall is used
- // internally; listxattr instead of llistxattr.
- {
- ASSERT_THAT(LIBC_NAMESPACE::listxattr(TEST_SYMLINK_NAME, nullptr, 0),
- Succeeds<ssize_t>(xattr_name_null_terminated_len));
-
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, xattr_name_null_terminated_len);
-
- char buffer[BUFFER_SIZE] = {};
- ASSERT_THAT(
- LIBC_NAMESPACE::listxattr(TEST_SYMLINK_NAME, buffer, BUFFER_SIZE),
- Succeeds(xattr_name_null_terminated_len));
- string_view result_str(buffer, xattr_name_null_terminated_len - 1);
- EXPECT_EQ(result_str, XATTR_NAME);
- }
-
- // Call with insufficient buffer size to check failing errno.
- {
- constexpr size_t BUFFER_SIZE = 14;
- ASSERT_LT(BUFFER_SIZE, xattr_name_null_terminated_len);
-
- char buffer[BUFFER_SIZE] = {};
- EXPECT_THAT(LIBC_NAMESPACE::listxattr(TEST_FILE_NAME, buffer, BUFFER_SIZE),
- Fails<ssize_t>(ERANGE));
- }
-}
-
-#if defined(LIBC_ADD_NULL_CHECKS)
-
-TEST(LlvmLibcListxattrTest, CrashOnNullPath) {
- EXPECT_DEATH(
- [] {
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::listxattr(nullptr, buffer, BUFFER_SIZE);
- },
- WITH_SIGNAL(-1));
-}
-
-#endif // LIBC_ADD_NULL_CHECKS
-
-} // namespace
diff --git a/libc/test/src/sys/xattr/llistxattr_test.cpp b/libc/test/src/sys/xattr/llistxattr_test.cpp
deleted file mode 100644
index bddb5516d4cd3..0000000000000
--- a/libc/test/src/sys/xattr/llistxattr_test.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Unit tests for llistxattr.
-///
-//===----------------------------------------------------------------------===//
-
-#include "hdr/sys_stat_macros.h"
-#include "src/__support/CPP/scope.h"
-#include "src/__support/OSUtil/linux/syscall.h"
-#include "src/__support/libc_errno.h"
-#include "src/fcntl/creat.h"
-#include "src/sys/xattr/llistxattr.h"
-#include "src/unistd/close.h"
-#include "src/unistd/symlink.h"
-#include "src/unistd/unlink.h"
-#include "test/UnitTest/ErrnoCheckingTest.h"
-#include "test/UnitTest/ErrnoSetterMatcher.h"
-#include "test/UnitTest/Test.h"
-#include <sys/syscall.h>
-
-namespace {
-
-using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
-using LlvmLibcLlistxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
-using LIBC_NAMESPACE::cpp::scope_exit;
-using LIBC_NAMESPACE::cpp::string_view;
-
-int recreate_test_file(const char *path) {
- LIBC_NAMESPACE::unlink(path);
- LIBC_NAMESPACE::libc_errno = 0;
- return LIBC_NAMESPACE::creat(path, S_IRWXU);
-}
-
-int recreate_test_symlink(const char *target, const char *linkpath) {
- LIBC_NAMESPACE::unlink(linkpath);
- LIBC_NAMESPACE::libc_errno = 0;
- return LIBC_NAMESPACE::symlink(target, linkpath);
-}
-
-TEST_F(LlvmLibcLlistxattrTest, NoExtendedAttributes) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/llistxattr_no_xattrs.txt");
-
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
-
- EXPECT_THAT(LIBC_NAMESPACE::llistxattr(TEST_FILE_NAME, nullptr, 0),
- Succeeds<ssize_t>(0));
-
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- ASSERT_THAT(LIBC_NAMESPACE::llistxattr(TEST_FILE_NAME, buffer, BUFFER_SIZE),
- Succeeds<ssize_t>(0));
-}
-
-TEST_F(LlvmLibcLlistxattrTest, WithUserExtendedAttribute) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/llistxattr_with_user_xattr.txt");
- constexpr const char *TEST_SYMLINK_TARGET = "llistxattr_with_user_xattr.txt";
- const LIBC_NAMESPACE::CString TEST_SYMLINK_NAME =
- libc_make_test_file_path("testdata/llistxattr_symlink.txt");
-
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
-
- ASSERT_THAT(recreate_test_symlink(TEST_SYMLINK_TARGET, TEST_SYMLINK_NAME),
- Succeeds(0));
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_SYMLINK_NAME), Succeeds(0));
- });
-
- string_view XATTR_NAME = "user.test_attr";
- string_view XATTR_VALUE = "test_value";
- ASSERT_EQ(0, LIBC_NAMESPACE::syscall_impl<int>(
- SYS_setxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), XATTR_VALUE.data(), XATTR_VALUE.size(),
- /* flags = */ 0));
- size_t xattr_name_null_terminated_len = XATTR_NAME.size() + 1;
-
- // Call with the test file path.
- {
- ASSERT_THAT(LIBC_NAMESPACE::llistxattr(TEST_FILE_NAME, nullptr, 0),
- Succeeds<ssize_t>(xattr_name_null_terminated_len));
-
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, xattr_name_null_terminated_len);
-
- char buffer[BUFFER_SIZE] = {};
- ASSERT_THAT(LIBC_NAMESPACE::llistxattr(TEST_FILE_NAME, buffer, BUFFER_SIZE),
- Succeeds(xattr_name_null_terminated_len));
- string_view result_str(buffer, xattr_name_null_terminated_len - 1);
- EXPECT_EQ(result_str, XATTR_NAME);
- }
-
- // Call with the symlink path to verify the correct syscall is used
- // internally; llistxattr instead of listxattr.
- {
- EXPECT_THAT(LIBC_NAMESPACE::llistxattr(TEST_SYMLINK_NAME, nullptr, 0),
- Succeeds<ssize_t>(0));
-
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, xattr_name_null_terminated_len);
-
- char buffer[BUFFER_SIZE] = {};
- EXPECT_THAT(
- LIBC_NAMESPACE::llistxattr(TEST_SYMLINK_NAME, buffer, BUFFER_SIZE),
- Succeeds<ssize_t>(0));
- }
-
- // Call with insufficient buffer size to check failing errno.
- {
- constexpr size_t BUFFER_SIZE = 14;
- ASSERT_LT(BUFFER_SIZE, xattr_name_null_terminated_len);
-
- char buffer[BUFFER_SIZE] = {};
- EXPECT_THAT(LIBC_NAMESPACE::llistxattr(TEST_FILE_NAME, buffer, BUFFER_SIZE),
- Fails<ssize_t>(ERANGE));
- }
-}
-
-#if defined(LIBC_ADD_NULL_CHECKS)
-
-TEST(LlvmLibcLlistxattrTest, CrashOnNullPath) {
- EXPECT_DEATH(
- [] {
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::llistxattr(nullptr, buffer, BUFFER_SIZE);
- },
- WITH_SIGNAL(-1));
-}
-
-#endif // LIBC_ADD_NULL_CHECKS
-
-} // namespace
diff --git a/libc/test/src/sys/xattr/lsetxattr_test.cpp b/libc/test/src/sys/xattr/lsetxattr_test.cpp
deleted file mode 100644
index 8edc6b4c70fe0..0000000000000
--- a/libc/test/src/sys/xattr/lsetxattr_test.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Unit tests for lsetxattr.
-///
-//===----------------------------------------------------------------------===//
-
-#include "hdr/sys_stat_macros.h"
-#include "hdr/sys_xattr_macros.h"
-#include "hdr/types/ssize_t.h"
-#include "src/__support/CPP/scope.h"
-#include "src/__support/CPP/string_view.h"
-#include "src/__support/OSUtil/linux/syscall.h"
-#include "src/__support/libc_errno.h"
-#include "src/fcntl/creat.h"
-#include "src/sys/xattr/lsetxattr.h"
-#include "src/unistd/close.h"
-#include "src/unistd/unlink.h"
-#include "test/UnitTest/ErrnoCheckingTest.h"
-#include "test/UnitTest/ErrnoSetterMatcher.h"
-#include "test/UnitTest/Test.h"
-#include <sys/syscall.h>
-
-namespace {
-
-using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
-using LlvmLibcLsetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
-using LIBC_NAMESPACE::cpp::scope_exit;
-using LIBC_NAMESPACE::cpp::string_view;
-
-int recreate_test_file(const char *path) {
- LIBC_NAMESPACE::unlink(path);
- LIBC_NAMESPACE::libc_errno = 0;
- return LIBC_NAMESPACE::creat(path, S_IRWXU);
-}
-
-TEST_F(LlvmLibcLsetxattrTest, SetAttributeDefaultFlags) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/lsetxattr_default_flags.txt");
-
- int fd = recreate_test_file(TEST_FILE_NAME);
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
- ASSERT_ERRNO_SUCCESS();
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
-
- // Set an attribute through the test file name.
- {
- string_view XATTR_NAME = "user.test_attr_through_file";
- string_view XATTR_VALUE = "test_value_through_file";
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
- char buffer[BUFFER_SIZE] = {};
-
- ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- XATTR_VALUE.data(),
- XATTR_VALUE.size(),
- /* flags = */ 0),
- Succeeds(0));
-
- ASSERT_EQ(static_cast<ssize_t>(XATTR_VALUE.size()),
- LIBC_NAMESPACE::syscall_impl<ssize_t>(
- SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), buffer, BUFFER_SIZE));
- EXPECT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
- }
-
- // TODO: Figure out if/how to test `lsetxattr` with a symlink path. The "user"
- // namespace extended attributes appear restricted to regular files and
- // directories. Attempting to set a "user" extended attribute on a symlink
- // results in EPERM.
-}
-
-TEST_F(LlvmLibcLsetxattrTest, SetAttributeWithNonzeroFlags) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/lsetxattr_nonzero_flags.txt");
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
-
- string_view XATTR_NAME = "user.test_attr";
- string_view XATTR_VALUE = "test_value";
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
- char buffer[BUFFER_SIZE] = {};
-
- // Try replace-only before attribute exists.
- ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- XATTR_VALUE.data(), XATTR_VALUE.size(),
- XATTR_REPLACE),
- Fails(ENODATA));
-
- ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- XATTR_VALUE.data(), XATTR_VALUE.size(),
- /* flags = */ XATTR_CREATE),
- Succeeds(0));
-
- ASSERT_EQ(static_cast<ssize_t>(XATTR_VALUE.size()),
- LIBC_NAMESPACE::syscall_impl<ssize_t>(
- SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), buffer, BUFFER_SIZE));
- ASSERT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
-
- // Replace-only now that the attribute exists.
- string_view NEW_XATTR_VALUE = "new_test_value";
- ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- NEW_XATTR_VALUE.data(),
- NEW_XATTR_VALUE.size(), XATTR_REPLACE),
- Succeeds(0));
-
- ASSERT_EQ(static_cast<ssize_t>(NEW_XATTR_VALUE.size()),
- LIBC_NAMESPACE::syscall_impl<ssize_t>(
- SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), buffer, BUFFER_SIZE));
- ASSERT_EQ(string_view(buffer, NEW_XATTR_VALUE.size()), NEW_XATTR_VALUE);
-
- // Try create-only when the attribute already exists.
- ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- XATTR_VALUE.data(), XATTR_VALUE.size(),
- XATTR_CREATE),
- Fails(EEXIST));
-}
-
-#if defined(LIBC_ADD_NULL_CHECKS)
-
-TEST_F(LlvmLibcLsetxattrTest, CrashOnNullPath) {
- EXPECT_DEATH(
- [] {
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::lsetxattr(nullptr, "user.attr", buffer, BUFFER_SIZE,
- /* flags = */ 0);
- },
- WITH_SIGNAL(-1));
-}
-
-TEST_F(LlvmLibcLsetxattrTest, CrashOnNullAttributeName) {
- EXPECT_DEATH(
- [] {
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::lsetxattr("testdata/file.txt", nullptr, buffer,
- BUFFER_SIZE, /* flags = */ 0);
- },
- WITH_SIGNAL(-1));
-}
-
-TEST_F(LlvmLibcLsetxattrTest, CrashOnNullBufferNonZeroSize) {
- EXPECT_DEATH(
- [] {
- LIBC_NAMESPACE::lsetxattr("testdata/file.txt", "user.attr", nullptr, 32,
- /* flags = */ 0);
- },
- WITH_SIGNAL(-1));
-}
-
-#endif // LIBC_ADD_NULL_CHECKS
-
-} // namespace
diff --git a/libc/test/src/sys/xattr/lxattr_test.cpp b/libc/test/src/sys/xattr/lxattr_test.cpp
new file mode 100644
index 0000000000000..f7e11b340db7b
--- /dev/null
+++ b/libc/test/src/sys/xattr/lxattr_test.cpp
@@ -0,0 +1,302 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for lgetxattr, lsetxattr, and, llistxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/sys_stat_macros.h"
+#include "hdr/sys_xattr_macros.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/CPP/scope.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/libc_errno.h"
+#include "src/fcntl/creat.h"
+#include "src/sys/xattr/lgetxattr.h"
+#include "src/sys/xattr/llistxattr.h"
+#include "src/sys/xattr/lsetxattr.h"
+#include "src/unistd/close.h"
+#include "src/unistd/symlink.h"
+#include "src/unistd/unlink.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+namespace {
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LlvmLibcLxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::cpp::scope_exit;
+using LIBC_NAMESPACE::cpp::string_view;
+
+int recreate_test_file(const char *path) {
+ LIBC_NAMESPACE::unlink(path);
+ LIBC_NAMESPACE::libc_errno = 0;
+ return LIBC_NAMESPACE::creat(path, S_IRWXU);
+}
+
+int recreate_test_symlink(const char *target, const char *linkpath) {
+ LIBC_NAMESPACE::unlink(linkpath);
+ LIBC_NAMESPACE::libc_errno = 0;
+ return LIBC_NAMESPACE::symlink(target, linkpath);
+}
+
+TEST_F(LlvmLibcLxattrTest, GetAndListWithNoAttributeSet) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/lxattr_unset_testfile.txt");
+
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+
+ EXPECT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_FILE_NAME,
+ "user.missing_test_attr", buffer,
+ BUFFER_SIZE),
+ Fails<ssize_t>(ENODATA));
+
+ EXPECT_THAT(LIBC_NAMESPACE::llistxattr(TEST_FILE_NAME, nullptr, 0),
+ Succeeds<ssize_t>(0));
+
+ EXPECT_THAT(LIBC_NAMESPACE::llistxattr(TEST_FILE_NAME, buffer, BUFFER_SIZE),
+ Succeeds<ssize_t>(0));
+}
+
+TEST_F(LlvmLibcLxattrTest, SetGetAndListWithUserExtendedAttribute) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/lxattr_testfile.txt");
+ constexpr const char *TEST_SYMLINK_TARGET = "lxattr_testfile.txt";
+ const LIBC_NAMESPACE::CString TEST_SYMLINK_NAME =
+ libc_make_test_file_path("testdata/lxattr_testsymlink.txt");
+
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit unlink_file([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+
+ ASSERT_THAT(recreate_test_symlink(TEST_SYMLINK_TARGET, TEST_SYMLINK_NAME),
+ Succeeds(0));
+ scope_exit unlink_symlink([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_SYMLINK_NAME), Succeeds(0));
+ });
+
+ string_view XATTR_NAME = "user.test_attr";
+ string_view XATTR_VALUE = "test_value";
+ ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ 0),
+ Succeeds(0));
+ size_t xattr_name_null_terminated_len = XATTR_NAME.size() + 1;
+
+ // Get and list using the test file path.
+ EXPECT_THAT(
+ LIBC_NAMESPACE::lgetxattr(TEST_FILE_NAME, XATTR_NAME.data(), nullptr, 0),
+ Succeeds<ssize_t>(XATTR_VALUE.size()));
+ EXPECT_THAT(LIBC_NAMESPACE::llistxattr(TEST_FILE_NAME, nullptr, 0),
+ Succeeds<ssize_t>(xattr_name_null_terminated_len));
+ {
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_NAME.size());
+
+ char buffer[BUFFER_SIZE] = {};
+ ASSERT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Succeeds(XATTR_VALUE.size()));
+ string_view result_str(buffer, XATTR_VALUE.size());
+ EXPECT_EQ(result_str, XATTR_VALUE);
+ }
+ {
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, xattr_name_null_terminated_len);
+
+ char buffer[BUFFER_SIZE] = {};
+ ASSERT_THAT(LIBC_NAMESPACE::llistxattr(TEST_FILE_NAME, buffer, BUFFER_SIZE),
+ Succeeds(xattr_name_null_terminated_len));
+ string_view result_str(buffer, xattr_name_null_terminated_len - 1);
+ EXPECT_EQ(result_str, XATTR_NAME);
+ }
+
+ // Get and list using the symlink path to verify the correct syscall is used
+ // internally; lgetxattr or llistxattr, and not getxattr or listxattr.
+ {
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, xattr_name_null_terminated_len);
+
+ char buffer[BUFFER_SIZE] = {};
+ EXPECT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_SYMLINK_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Fails<ssize_t>(ENODATA));
+ EXPECT_THAT(
+ LIBC_NAMESPACE::llistxattr(TEST_SYMLINK_NAME, buffer, BUFFER_SIZE),
+ Succeeds<ssize_t>(0));
+ }
+
+ // Get and list with insufficient buffer size, and get with missing attribute
+ // on the file to check failing errno.
+ {
+ constexpr size_t BUFFER_SIZE = 8;
+ ASSERT_LT(BUFFER_SIZE, xattr_name_null_terminated_len);
+ ASSERT_LT(BUFFER_SIZE, XATTR_VALUE.size());
+ char buffer[BUFFER_SIZE] = {};
+
+ EXPECT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Fails<ssize_t>(ERANGE));
+
+ EXPECT_THAT(LIBC_NAMESPACE::llistxattr(TEST_FILE_NAME, buffer, BUFFER_SIZE),
+ Fails<ssize_t>(ERANGE));
+
+ EXPECT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_FILE_NAME,
+ "user.missing_test_attr", buffer,
+ BUFFER_SIZE),
+ Fails<ssize_t>(ENODATA));
+ }
+}
+
+TEST_F(LlvmLibcLxattrTest, SetAttributeWithNonzeroFlags) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/lxattr_nonzero_flags_testfile.txt");
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+
+ string_view XATTR_NAME = "user.test_attr";
+ string_view XATTR_VALUE = "test_value";
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+ char buffer[BUFFER_SIZE] = {};
+
+ // Try replace-only before attribute exists.
+ ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ XATTR_REPLACE),
+ Fails(ENODATA));
+
+ ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ XATTR_CREATE),
+ Succeeds(0));
+
+ EXPECT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Succeeds<ssize_t>(XATTR_VALUE.size()));
+ ASSERT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
+
+ // Replace-only now that the attribute does exist.
+ string_view NEW_XATTR_VALUE = "new_test_value";
+ ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ NEW_XATTR_VALUE.data(),
+ NEW_XATTR_VALUE.size(), XATTR_REPLACE),
+ Succeeds(0));
+
+ EXPECT_THAT(LIBC_NAMESPACE::lgetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Succeeds<ssize_t>(NEW_XATTR_VALUE.size()));
+ ASSERT_EQ(string_view(buffer, NEW_XATTR_VALUE.size()), NEW_XATTR_VALUE);
+
+ // Try create-only when the attribute already exists.
+ ASSERT_THAT(LIBC_NAMESPACE::lsetxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ XATTR_CREATE),
+ Fails(EEXIST));
+}
+
+#if 1 // defined(LIBC_ADD_NULL_CHECKS)
+
+TEST_F(LlvmLibcLxattrTest, SetCrashesOnNullPath) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::lsetxattr(nullptr, "user.attr", buffer, BUFFER_SIZE,
+ /* flags = */ 0);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcLxattrTest, SetCrashesOnNullAttributeName) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::lsetxattr("testdata/file.txt", nullptr, buffer,
+ BUFFER_SIZE, /* flags = */ 0);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcLxattrTest, SetCrashesOnNullBufferNonZeroSize) {
+ EXPECT_DEATH(
+ [] {
+ LIBC_NAMESPACE::lsetxattr("testdata/file.txt", "user.attr", nullptr, 32,
+ /* flags = */ 0);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcLxattrTest, GetCrashesOnNullPath) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::lgetxattr(nullptr, "user.attr", buffer, BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcLxattrTest, GetCrashesOnNullAttributeName) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::lgetxattr("testdata/file.txt", nullptr, buffer,
+ BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcLxattrTest, GetCrashesOnNullBufferNonZeroSize) {
+ EXPECT_DEATH(
+ [] {
+ LIBC_NAMESPACE::lgetxattr("testdata/file.txt", "user.attr", nullptr,
+ 32);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST(LlvmLibcLxattrTest, ListCrashesOnNullPath) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::llistxattr(nullptr, buffer, BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcLxattrTest, ListCrashesOnNullBufferNonZeroSize) {
+ EXPECT_DEATH(
+ [] { LIBC_NAMESPACE::llistxattr("testdata/file.txt", nullptr, 32); },
+ WITH_SIGNAL(-1));
+}
+
+#endif // LIBC_ADD_NULL_CHECKS
+
+} // namespace
diff --git a/libc/test/src/sys/xattr/setxattr_test.cpp b/libc/test/src/sys/xattr/setxattr_test.cpp
deleted file mode 100644
index ab402fe0b40dc..0000000000000
--- a/libc/test/src/sys/xattr/setxattr_test.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Unit tests for setxattr.
-///
-//===----------------------------------------------------------------------===//
-
-#include "hdr/sys_stat_macros.h"
-#include "hdr/sys_xattr_macros.h"
-#include "hdr/types/ssize_t.h"
-#include "src/__support/CPP/scope.h"
-#include "src/__support/CPP/string_view.h"
-#include "src/__support/OSUtil/linux/syscall.h"
-#include "src/__support/libc_errno.h"
-#include "src/fcntl/creat.h"
-#include "src/sys/xattr/setxattr.h"
-#include "src/unistd/close.h"
-#include "src/unistd/symlink.h"
-#include "src/unistd/unlink.h"
-#include "test/UnitTest/ErrnoCheckingTest.h"
-#include "test/UnitTest/ErrnoSetterMatcher.h"
-#include "test/UnitTest/Test.h"
-#include <sys/syscall.h>
-
-namespace {
-
-using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
-using LlvmLibcSetxattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
-using LIBC_NAMESPACE::cpp::scope_exit;
-using LIBC_NAMESPACE::cpp::string_view;
-
-int recreate_test_file(const char *path) {
- LIBC_NAMESPACE::unlink(path);
- LIBC_NAMESPACE::libc_errno = 0;
- return LIBC_NAMESPACE::creat(path, S_IRWXU);
-}
-
-int recreate_test_symlink(const char *target, const char *linkpath) {
- LIBC_NAMESPACE::unlink(linkpath);
- LIBC_NAMESPACE::libc_errno = 0;
- return LIBC_NAMESPACE::symlink(target, linkpath);
-}
-
-TEST_F(LlvmLibcSetxattrTest, SetAttributeDefaultFlags) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/setxattr_default_flags.txt");
- constexpr const char *TEST_SYMLINK_TARGET = "setxattr_default_flags.txt";
- const LIBC_NAMESPACE::CString TEST_SYMLINK_NAME =
- libc_make_test_file_path("testdata/setxattr_default_flags_symlink.txt");
-
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- scope_exit unlink_file([&] {
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
-
- ASSERT_THAT(recreate_test_symlink(TEST_SYMLINK_TARGET, TEST_SYMLINK_NAME),
- Succeeds(0));
- scope_exit unlink_symlink([&] {
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_SYMLINK_NAME), Succeeds(0));
- });
-
- // Set an attribute through the test file name.
- {
- string_view XATTR_NAME = "user.test_attr_through_file";
- string_view XATTR_VALUE = "test_value_through_file";
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
- char buffer[BUFFER_SIZE] = {};
-
- ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- XATTR_VALUE.data(), XATTR_VALUE.size(),
- /* flags = */ 0),
- Succeeds(0));
-
- ASSERT_EQ(static_cast<ssize_t>(XATTR_VALUE.size()),
- LIBC_NAMESPACE::syscall_impl<ssize_t>(
- SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), buffer, BUFFER_SIZE));
- EXPECT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
- }
-
- // Set another attribute through the symlink to verify the correct syscall is
- // used internally; setxattr instead of lsetxattr.
- {
- string_view XATTR_NAME = "user.test_attr_through_symlink";
- string_view XATTR_VALUE = "test_value_through_symlink";
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
- char buffer[BUFFER_SIZE] = {};
-
- ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_SYMLINK_NAME, XATTR_NAME.data(),
- XATTR_VALUE.data(), XATTR_VALUE.size(),
- /* flags = */ 0),
- Succeeds(0));
-
- EXPECT_EQ(static_cast<ssize_t>(XATTR_VALUE.size()),
- LIBC_NAMESPACE::syscall_impl<ssize_t>(
- SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), buffer, BUFFER_SIZE));
- EXPECT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
- }
-}
-
-TEST_F(LlvmLibcSetxattrTest, SetAttributeWithNonzeroFlags) {
- const LIBC_NAMESPACE::CString TEST_FILE_NAME =
- libc_make_test_file_path("testdata/setxattr_nonzero_flags.txt");
- int fd = recreate_test_file(TEST_FILE_NAME);
- ASSERT_ERRNO_SUCCESS();
- scope_exit cleanup([&] {
- ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
- });
- ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
-
- string_view XATTR_NAME = "user.test_attr";
- string_view XATTR_VALUE = "test_value";
- constexpr size_t BUFFER_SIZE = 32;
- ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
- char buffer[BUFFER_SIZE] = {};
-
- // Try replace-only before attribute exists.
- ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- XATTR_VALUE.data(), XATTR_VALUE.size(),
- XATTR_REPLACE),
- Fails(ENODATA));
-
- ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- XATTR_VALUE.data(), XATTR_VALUE.size(),
- /* flags = */ XATTR_CREATE),
- Succeeds(0));
-
- ASSERT_EQ(static_cast<ssize_t>(XATTR_VALUE.size()),
- LIBC_NAMESPACE::syscall_impl<ssize_t>(
- SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), buffer, BUFFER_SIZE));
- ASSERT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
-
- // Replace-only now that the attribute exists.
- string_view NEW_XATTR_VALUE = "new_test_value";
- ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- NEW_XATTR_VALUE.data(),
- NEW_XATTR_VALUE.size(), XATTR_REPLACE),
- Succeeds(0));
-
- ASSERT_EQ(static_cast<ssize_t>(NEW_XATTR_VALUE.size()),
- LIBC_NAMESPACE::syscall_impl<ssize_t>(
- SYS_getxattr, static_cast<const char *>(TEST_FILE_NAME),
- XATTR_NAME.data(), buffer, BUFFER_SIZE));
- ASSERT_EQ(string_view(buffer, NEW_XATTR_VALUE.size()), NEW_XATTR_VALUE);
-
- // Try create-only when the attribute already exists.
- ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
- XATTR_VALUE.data(), XATTR_VALUE.size(),
- XATTR_CREATE),
- Fails(EEXIST));
-}
-
-#if defined(LIBC_ADD_NULL_CHECKS)
-
-TEST_F(LlvmLibcSetxattrTest, CrashOnNullPath) {
- EXPECT_DEATH(
- [] {
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::setxattr(nullptr, "user.attr", buffer, BUFFER_SIZE,
- /* flags = */ 0);
- },
- WITH_SIGNAL(-1));
-}
-
-TEST_F(LlvmLibcSetxattrTest, CrashOnNullAttributeName) {
- EXPECT_DEATH(
- [] {
- constexpr size_t BUFFER_SIZE = 32;
- char buffer[BUFFER_SIZE] = {};
- LIBC_NAMESPACE::setxattr("testdata/file.txt", nullptr, buffer,
- BUFFER_SIZE, /* flags = */ 0);
- },
- WITH_SIGNAL(-1));
-}
-
-TEST_F(LlvmLibcSetxattrTest, CrashOnNullBufferNonZeroSize) {
- EXPECT_DEATH(
- [] {
- LIBC_NAMESPACE::setxattr("testdata/file.txt", "user.attr", nullptr, 32,
- /* flags = */ 0);
- },
- WITH_SIGNAL(-1));
-}
-
-#endif // LIBC_ADD_NULL_CHECKS
-
-} // namespace
diff --git a/libc/test/src/sys/xattr/xattr_test.cpp b/libc/test/src/sys/xattr/xattr_test.cpp
new file mode 100644
index 0000000000000..f14ea03816617
--- /dev/null
+++ b/libc/test/src/sys/xattr/xattr_test.cpp
@@ -0,0 +1,336 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for getxattr, setxattr, and, listxattr.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/sys_stat_macros.h"
+#include "hdr/sys_xattr_macros.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/ssize_t.h"
+#include "src/__support/CPP/scope.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/libc_errno.h"
+#include "src/fcntl/creat.h"
+#include "src/sys/xattr/getxattr.h"
+#include "src/sys/xattr/listxattr.h"
+#include "src/sys/xattr/setxattr.h"
+#include "src/unistd/close.h"
+#include "src/unistd/symlink.h"
+#include "src/unistd/unlink.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+namespace {
+
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+using LlvmLibcXattrTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::cpp::scope_exit;
+using LIBC_NAMESPACE::cpp::string_view;
+
+int recreate_test_file(const char *path) {
+ LIBC_NAMESPACE::unlink(path);
+ LIBC_NAMESPACE::libc_errno = 0;
+ return LIBC_NAMESPACE::creat(path, S_IRWXU);
+}
+
+int recreate_test_symlink(const char *target, const char *linkpath) {
+ LIBC_NAMESPACE::unlink(linkpath);
+ LIBC_NAMESPACE::libc_errno = 0;
+ return LIBC_NAMESPACE::symlink(target, linkpath);
+}
+
+TEST_F(LlvmLibcXattrTest, GetAndListWithNoAttributeSet) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/xattr_unset_testfile.txt");
+
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+
+ EXPECT_THAT(LIBC_NAMESPACE::getxattr(TEST_FILE_NAME, "user.missing_test_attr",
+ buffer, BUFFER_SIZE),
+ Fails<ssize_t>(ENODATA));
+
+ EXPECT_THAT(LIBC_NAMESPACE::listxattr(TEST_FILE_NAME, nullptr, 0),
+ Succeeds<ssize_t>(0));
+
+ EXPECT_THAT(LIBC_NAMESPACE::listxattr(TEST_FILE_NAME, buffer, BUFFER_SIZE),
+ Succeeds<ssize_t>(0));
+}
+
+TEST_F(LlvmLibcXattrTest, SetGetAndListWithUserExtendedAttribute) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/xattr_testfile.txt");
+ constexpr const char *TEST_SYMLINK_TARGET = "xattr_testfile.txt";
+ const LIBC_NAMESPACE::CString TEST_SYMLINK_NAME =
+ libc_make_test_file_path("testdata/xattr_testsymlink.txt");
+
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit unlink_file([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+
+ ASSERT_THAT(recreate_test_symlink(TEST_SYMLINK_TARGET, TEST_SYMLINK_NAME),
+ Succeeds(0));
+ scope_exit unlink_symlink([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_SYMLINK_NAME), Succeeds(0));
+ });
+
+ string_view XATTR_NAME = "user.test_attr";
+ string_view XATTR_VALUE = "test_value";
+ ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ 0),
+ Succeeds(0));
+ size_t xattr_name_null_terminated_len = XATTR_NAME.size() + 1;
+
+ // Get and list using the test file path.
+ EXPECT_THAT(
+ LIBC_NAMESPACE::getxattr(TEST_FILE_NAME, XATTR_NAME.data(), nullptr, 0),
+ Succeeds<ssize_t>(XATTR_VALUE.size()));
+ EXPECT_THAT(LIBC_NAMESPACE::listxattr(TEST_FILE_NAME, nullptr, 0),
+ Succeeds<ssize_t>(xattr_name_null_terminated_len));
+ {
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_NAME.size());
+
+ char buffer[BUFFER_SIZE] = {};
+ ASSERT_THAT(LIBC_NAMESPACE::getxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Succeeds(XATTR_VALUE.size()));
+ string_view result_str(buffer, XATTR_VALUE.size());
+ EXPECT_EQ(result_str, XATTR_VALUE);
+ }
+ {
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, xattr_name_null_terminated_len);
+
+ char buffer[BUFFER_SIZE] = {};
+ ASSERT_THAT(LIBC_NAMESPACE::listxattr(TEST_FILE_NAME, buffer, BUFFER_SIZE),
+ Succeeds(xattr_name_null_terminated_len));
+ string_view result_str(buffer, xattr_name_null_terminated_len - 1);
+ EXPECT_EQ(result_str, XATTR_NAME);
+ }
+
+ // Get and list using the symlink path to verify the correct syscall is used
+ // internally; getxattr or listxattr, and not lgetxattr or llistxattr.
+ EXPECT_THAT(LIBC_NAMESPACE::getxattr(TEST_SYMLINK_NAME, XATTR_NAME.data(),
+ nullptr, 0),
+ Succeeds<ssize_t>(XATTR_VALUE.size()));
+ EXPECT_THAT(LIBC_NAMESPACE::listxattr(TEST_SYMLINK_NAME, nullptr, 0),
+ Succeeds<ssize_t>(xattr_name_null_terminated_len));
+ {
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_NAME.size());
+
+ char buffer[BUFFER_SIZE] = {};
+ ASSERT_THAT(LIBC_NAMESPACE::getxattr(TEST_SYMLINK_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Succeeds(XATTR_VALUE.size()));
+ string_view result_str(buffer, XATTR_VALUE.size());
+ EXPECT_EQ(result_str, XATTR_VALUE);
+ }
+ {
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, xattr_name_null_terminated_len);
+
+ char buffer[BUFFER_SIZE] = {};
+ ASSERT_THAT(
+ LIBC_NAMESPACE::listxattr(TEST_SYMLINK_NAME, buffer, BUFFER_SIZE),
+ Succeeds(xattr_name_null_terminated_len));
+ string_view result_str(buffer, xattr_name_null_terminated_len - 1);
+ EXPECT_EQ(result_str, XATTR_NAME);
+ }
+
+ // Set another attribute through the symlink to verify the correct syscall is
+ // used internally; setxattr instead of lsetxattr.
+ {
+ string_view NEW_XATTR_NAME = "user.test_attr_through_symlink";
+ string_view NEW_XATTR_VALUE = "test_value_through_symlink";
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, NEW_XATTR_VALUE.size());
+ char buffer[BUFFER_SIZE] = {};
+
+ ASSERT_THAT(
+ LIBC_NAMESPACE::setxattr(TEST_SYMLINK_NAME, NEW_XATTR_NAME.data(),
+ NEW_XATTR_VALUE.data(), NEW_XATTR_VALUE.size(),
+ /* flags = */ 0),
+ Succeeds(0));
+
+ EXPECT_THAT(LIBC_NAMESPACE::getxattr(TEST_FILE_NAME, NEW_XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Succeeds<ssize_t>(NEW_XATTR_VALUE.size()));
+ ASSERT_EQ(string_view(buffer, NEW_XATTR_VALUE.size()), NEW_XATTR_VALUE);
+ }
+
+ // Get and list with insufficient buffer size, and get with missing attribute
+ // to check failing errno.
+ {
+ constexpr size_t BUFFER_SIZE = 8;
+ ASSERT_LT(BUFFER_SIZE, xattr_name_null_terminated_len);
+ ASSERT_LT(BUFFER_SIZE, XATTR_VALUE.size());
+ char buffer[BUFFER_SIZE] = {};
+
+ EXPECT_THAT(LIBC_NAMESPACE::getxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Fails<ssize_t>(ERANGE));
+
+ EXPECT_THAT(LIBC_NAMESPACE::listxattr(TEST_FILE_NAME, buffer, BUFFER_SIZE),
+ Fails<ssize_t>(ERANGE));
+
+ EXPECT_THAT(LIBC_NAMESPACE::getxattr(TEST_FILE_NAME,
+ "user.missing_test_attr", buffer,
+ BUFFER_SIZE),
+ Fails<ssize_t>(ENODATA));
+ }
+}
+
+TEST_F(LlvmLibcXattrTest, SetAttributeWithNonzeroFlags) {
+ const LIBC_NAMESPACE::CString TEST_FILE_NAME =
+ libc_make_test_file_path("testdata/xattr_nonzero_flags_testfile.txt");
+ int fd = recreate_test_file(TEST_FILE_NAME);
+ ASSERT_ERRNO_SUCCESS();
+ scope_exit cleanup([&] {
+ ASSERT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE_NAME), Succeeds(0));
+ });
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+
+ string_view XATTR_NAME = "user.test_attr";
+ string_view XATTR_VALUE = "test_value";
+ constexpr size_t BUFFER_SIZE = 32;
+ ASSERT_GE(BUFFER_SIZE, XATTR_VALUE.size());
+ char buffer[BUFFER_SIZE] = {};
+
+ // Try replace-only before attribute exists.
+ ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ XATTR_REPLACE),
+ Fails(ENODATA));
+
+ ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ /* flags = */ XATTR_CREATE),
+ Succeeds(0));
+
+ EXPECT_THAT(LIBC_NAMESPACE::getxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Succeeds<ssize_t>(XATTR_VALUE.size()));
+ ASSERT_EQ(string_view(buffer, XATTR_VALUE.size()), XATTR_VALUE);
+
+ // Replace-only now that the attribute does exist.
+ string_view NEW_XATTR_VALUE = "new_test_value";
+ ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ NEW_XATTR_VALUE.data(),
+ NEW_XATTR_VALUE.size(), XATTR_REPLACE),
+ Succeeds(0));
+
+ EXPECT_THAT(LIBC_NAMESPACE::getxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ buffer, BUFFER_SIZE),
+ Succeeds<ssize_t>(NEW_XATTR_VALUE.size()));
+ ASSERT_EQ(string_view(buffer, NEW_XATTR_VALUE.size()), NEW_XATTR_VALUE);
+
+ // Try create-only when the attribute already exists.
+ ASSERT_THAT(LIBC_NAMESPACE::setxattr(TEST_FILE_NAME, XATTR_NAME.data(),
+ XATTR_VALUE.data(), XATTR_VALUE.size(),
+ XATTR_CREATE),
+ Fails(EEXIST));
+}
+
+#if 1 // defined(LIBC_ADD_NULL_CHECKS)
+
+TEST_F(LlvmLibcXattrTest, SetCrashesOnNullPath) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::setxattr(nullptr, "user.attr", buffer, BUFFER_SIZE,
+ /* flags = */ 0);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcXattrTest, SetCrashesOnNullAttributeName) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::setxattr("testdata/file.txt", nullptr, buffer,
+ BUFFER_SIZE, /* flags = */ 0);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcXattrTest, SetCrashesOnNullBufferNonZeroSize) {
+ EXPECT_DEATH(
+ [] {
+ LIBC_NAMESPACE::setxattr("testdata/file.txt", "user.attr", nullptr, 32,
+ /* flags = */ 0);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcXattrTest, GetCrashesOnNullPath) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::getxattr(nullptr, "user.attr", buffer, BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcXattrTest, GetCrashesOnNullAttributeName) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::getxattr("testdata/file.txt", nullptr, buffer,
+ BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcXattrTest, GetCrashesOnNullBufferNonZeroSize) {
+ EXPECT_DEATH(
+ [] {
+ LIBC_NAMESPACE::getxattr("testdata/file.txt", "user.attr", nullptr, 32);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST(LlvmLibcXattrTest, ListCrashesOnNullPath) {
+ EXPECT_DEATH(
+ [] {
+ constexpr size_t BUFFER_SIZE = 32;
+ char buffer[BUFFER_SIZE] = {};
+ LIBC_NAMESPACE::listxattr(nullptr, buffer, BUFFER_SIZE);
+ },
+ WITH_SIGNAL(-1));
+}
+
+TEST_F(LlvmLibcXattrTest, ListCrashesOnNullBufferNonZeroSize) {
+ EXPECT_DEATH(
+ [] { LIBC_NAMESPACE::listxattr("testdata/file.txt", nullptr, 32); },
+ WITH_SIGNAL(-1));
+}
+
+#endif // LIBC_ADD_NULL_CHECKS
+
+} // namespace
>From dc8e0353bab90f0a62bfb858d27750219a58292e Mon Sep 17 00:00:00 2001
From: Alex Strelnikov <strel at google.com>
Date: Thu, 24 Sep 2026 14:44:18 +0000
Subject: [PATCH 6/6] Sort entrypoint lists
---
libc/config/linux/aarch64/entrypoints.txt | 8 ++++----
libc/config/linux/x86_64/entrypoints.txt | 8 ++++----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 20cff8a4b8f2d..b5b80f8863b38 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -386,14 +386,14 @@ set(TARGET_LIBC_ENTRYPOINTS
# sys/xattr.h entrypoints
libc.src.sys.xattr.fgetxattr
+ libc.src.sys.xattr.flistxattr
+ libc.src.sys.xattr.fsetxattr
libc.src.sys.xattr.getxattr
libc.src.sys.xattr.lgetxattr
- libc.src.sys.xattr.fsetxattr
- libc.src.sys.xattr.setxattr
- libc.src.sys.xattr.lsetxattr
- libc.src.sys.xattr.flistxattr
libc.src.sys.xattr.listxattr
libc.src.sys.xattr.llistxattr
+ libc.src.sys.xattr.lsetxattr
+ libc.src.sys.xattr.setxattr
# sys/prctl.h entrypoints
libc.src.sys.prctl.prctl
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 2e5b944eb2852..9da65debef0cf 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -425,14 +425,14 @@ set(TARGET_LIBC_ENTRYPOINTS
# sys/xattr.h entrypoints
libc.src.sys.xattr.fgetxattr
+ libc.src.sys.xattr.flistxattr
+ libc.src.sys.xattr.fsetxattr
libc.src.sys.xattr.getxattr
libc.src.sys.xattr.lgetxattr
- libc.src.sys.xattr.fsetxattr
- libc.src.sys.xattr.setxattr
- libc.src.sys.xattr.lsetxattr
- libc.src.sys.xattr.flistxattr
libc.src.sys.xattr.listxattr
libc.src.sys.xattr.llistxattr
+ libc.src.sys.xattr.lsetxattr
+ libc.src.sys.xattr.setxattr
# sys/prctl.h entrypoints
libc.src.sys.prctl.prctl
More information about the libc-commits
mailing list