HAVE_PWRITEV2 = @have_pwritev2@
HAVE_COPY_FILE_RANGE = @have_copy_file_range@
HAVE_CACHESTAT = @have_cachestat@
+HAVE_FILE_GETATTR = @have_file_getattr@
NEED_INTERNAL_FSXATTR = @need_internal_fsxattr@
NEED_INTERNAL_FSCRYPT_ADD_KEY_ARG = @need_internal_fscrypt_add_key_arg@
NEED_INTERNAL_FSCRYPT_POLICY_V2 = @need_internal_fscrypt_policy_v2@
GCFLAGS += -DENABLE_GETTEXT
endif
+ifeq ($(HAVE_FILE_GETATTR),yes)
+LCFLAGS += -DHAVE_FILE_GETATTR
+endif
+
# Override these if C++ needs other options
SANITIZER_CXXFLAGS = $(SANITIZER_CFLAGS)
GCXXFLAGS = $(GCFLAGS)
#include <sys/param.h>
#include <sys/sysmacros.h>
#include <sys/stat.h>
+#include <sys/syscall.h>
#include <inttypes.h>
#include <malloc.h>
#include <getopt.h>
};
#endif
+/*
+ * Use FILE_ATTR_SIZE_VER0 (linux/fs.h) instead of build system
+ * HAVE_FILE_GETATTR as this header could be included in other places where
+ * HAVE_FILE_GETATTR is not defined (e.g. xfstests's conftest.c in ./configure)
+ */
+#ifndef FILE_ATTR_SIZE_VER0
+/*
+ * We need to define file_attr if it's missing to know how to convert it to
+ * fsxattr
+ */
+struct file_attr {
+ __u32 fa_xflags;
+ __u32 fa_extsize;
+ __u32 fa_nextents;
+ __u32 fa_projid;
+ __u32 fa_cowextsize;
+};
+#endif
+
#ifndef FS_IOC_FSGETXATTR
/*
* Flags for the fsx_xflags field
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Red Hat, Inc.
+ * All Rights Reserved.
+ */
+
+#include "file_attr.h"
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <asm/types.h>
+#include <fcntl.h>
+
+static void
+file_attr_to_fsxattr(
+ const struct file_attr *fa,
+ struct fsxattr *fsxa)
+{
+ memset(fsxa, 0, sizeof(struct fsxattr));
+
+ fsxa->fsx_xflags = fa->fa_xflags;
+ fsxa->fsx_extsize = fa->fa_extsize;
+ fsxa->fsx_nextents = fa->fa_nextents;
+ fsxa->fsx_projid = fa->fa_projid;
+ fsxa->fsx_cowextsize = fa->fa_cowextsize;
+}
+
+static void
+fsxattr_to_file_attr(
+ const struct fsxattr *fsxa,
+ struct file_attr *fa)
+{
+ memset(fa, 0, sizeof(struct file_attr));
+
+ fa->fa_xflags = fsxa->fsx_xflags;
+ fa->fa_extsize = fsxa->fsx_extsize;
+ fa->fa_nextents = fsxa->fsx_nextents;
+ fa->fa_projid = fsxa->fsx_projid;
+ fa->fa_cowextsize = fsxa->fsx_cowextsize;
+}
+
+int
+xfrog_file_getattr(
+ const int dfd,
+ const char *path,
+ const struct stat *stat,
+ struct file_attr *fa,
+ const unsigned int at_flags)
+{
+ int error;
+ int fd;
+ struct fsxattr fsxa;
+
+#ifdef HAVE_FILE_GETATTR
+ error = syscall(__NR_file_getattr, dfd, path, fa,
+ sizeof(struct file_attr), at_flags);
+ if (error && errno != ENOSYS)
+ return error;
+
+ if (!error)
+ return error;
+#endif
+
+ if (SPECIAL_FILE(stat->st_mode)) {
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+
+ fd = open(path, O_RDONLY|O_NOCTTY);
+ if (fd == -1)
+ return fd;
+
+ error = ioctl(fd, FS_IOC_FSGETXATTR, &fsxa);
+ close(fd);
+ if (error)
+ return error;
+
+ fsxattr_to_file_attr(&fsxa, fa);
+
+ return error;
+}
+
+int
+xfrog_file_setattr(
+ const int dfd,
+ const char *path,
+ const struct stat *stat,
+ struct file_attr *fa,
+ const unsigned int at_flags)
+{
+ int error;
+ int fd;
+ struct fsxattr fsxa;
+
+#ifdef HAVE_FILE_GETATTR /* file_get/setattr goes together */
+ error = syscall(__NR_file_setattr, dfd, path, fa,
+ sizeof(struct file_attr), at_flags);
+ if (error && errno != ENOSYS)
+ return error;
+
+ if (!error)
+ return error;
+#endif
+
+ if (SPECIAL_FILE(stat->st_mode)) {
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+
+ fd = open(path, O_RDONLY|O_NOCTTY);
+ if (fd == -1)
+ return fd;
+
+ file_attr_to_fsxattr(fa, &fsxa);
+
+ error = ioctl(fd, FS_IOC_FSSETXATTR, fa);
+ close(fd);
+
+ return error;
+}
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2025 Red Hat, Inc.
+ * All Rights Reserved.
+ */
+#ifndef __LIBFROG_FILE_ATTR_H__
+#define __LIBFROG_FILE_ATTR_H__
+
+#include "linux.h"
+#include <sys/stat.h>
+
+#define SPECIAL_FILE(x) \
+ (S_ISCHR((x)) \
+ || S_ISBLK((x)) \
+ || S_ISFIFO((x)) \
+ || S_ISLNK((x)) \
+ || S_ISSOCK((x)))
+
+int
+xfrog_file_getattr(
+ const int dfd,
+ const char *path,
+ const struct stat *stat,
+ struct file_attr *fa,
+ const unsigned int at_flags);
+
+int
+xfrog_file_setattr(
+ const int dfd,
+ const char *path,
+ const struct stat *stat,
+ struct file_attr *fa,
+ const unsigned int at_flags);
+
+#endif /* __LIBFROG_FILE_ATTR_H__ */
AC_SUBST(lto_cflags)
AC_SUBST(lto_ldflags)
])
+
+#
+# Check if we have a file_getattr system call (Linux)
+#
+AC_DEFUN([AC_HAVE_FILE_GETATTR],
+ [AC_MSG_CHECKING([for file_getattr syscall])
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([[
+#define _GNU_SOURCE
+#include <sys/syscall.h>
+#include <unistd.h>
+ ]], [[
+syscall(__NR_file_getattr, 0, 0, 0, 0, 0);
+ ]])
+ ], have_file_getattr=yes
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no))
+ AC_SUBST(have_file_getattr)
+ ])