// SPDX-License-Identifier: GPL-2.0

#ifndef XFS_IO_STATX_H
#define XFS_IO_STATX_H

#include <unistd.h>
#include <sys/syscall.h>

#ifndef AT_EMPTY_PATH
#define AT_EMPTY_PATH	0x1000
#endif

#ifndef AT_STATX_SYNC_TYPE
#define AT_STATX_SYNC_TYPE      0x6000  /* Type of synchronisation required from statx() */
#define AT_STATX_SYNC_AS_STAT   0x0000  /* - Do whatever stat() does */
#define AT_STATX_FORCE_SYNC     0x2000  /* - Force the attributes to be sync'd with the server */
#define AT_STATX_DONT_SYNC      0x4000  /* - Don't sync attributes with the server */
#endif

#ifndef AT_NO_AUTOMOUNT
#define AT_NO_AUTOMOUNT		0x800	/* Suppress terminal automount traversal */
#endif

#ifndef __NR_statx
# if defined(__i386__) || defined(__powerpc__)
#  define __NR_statx 383
# elif defined (__x86_64__)
#  if defined (__ILP32__)
#   define __NR_statx (__X32_SYSCALL_BIT + 332)
#  else
#   define __NR_statx 332
#  endif
# endif
#endif


#ifndef STATX_TYPE
/* Pick up kernel definitions if glibc didn't already provide them */
#include <linux/stat.h>
#endif

#ifndef STATX_TYPE
/* Local definitions if glibc & kernel headers didn't already provide them */

/*
 * Timestamp structure for the timestamps in struct statx.
 *
 * tv_sec holds the number of seconds before (negative) or after (positive)
 * 00:00:00 1st January 1970 UTC.
 *
 * tv_nsec holds a number of nanoseconds before (0..-999,999,999 if tv_sec is
 * negative) or after (0..999,999,999 if tv_sec is positive) the tv_sec time.
 *
 * Note that if both tv_sec and tv_nsec are non-zero, then the two values must
 * either be both positive or both negative.
 *
 * __reserved is held in case we need a yet finer resolution.
 */
struct statx_timestamp {
	__s64	tv_sec;
	__s32	tv_nsec;
	__s32	__reserved;
};
#endif

/*
 * Structures for the extended file attribute retrieval system call
 * (statx()).
 *
 * The caller passes a mask of what they're specifically interested in as a
 * parameter to statx().  What statx() actually got will be indicated in
 * st_mask upon return.
 *
 * For each bit in the mask argument:
 *
 * - if the datum is not supported:
 *
 *   - the bit will be cleared, and
 *
 *   - the datum will be set to an appropriate fabricated value if one is
 *     available (eg. CIFS can take a default uid and gid), otherwise
 *
 *   - the field will be cleared;
 *
 * - otherwise, if explicitly requested:
 *
 *   - the datum will be synchronised to the server if AT_STATX_FORCE_SYNC is
 *     set or if the datum is considered out of date, and
 *
 *   - the field will be filled in and the bit will be set;
 *
 * - otherwise, if not requested, but available in approximate form without any
 *   effort, it will be filled in anyway, and the bit will be set upon return
 *   (it might not be up to date, however, and no attempt will be made to
 *   synchronise the internal state first);
 *
 * - otherwise the field and the bit will be cleared before returning.
 *
 * Items in STATX_BASIC_STATS may be marked unavailable on return, but they
 * will have values installed for compatibility purposes so that stat() and
 * co. can be emulated in userspace.
 */
#ifdef OVERRIDE_SYSTEM_STATX
#undef statx
struct statx {
	/* 0x00 */
	__u32	stx_mask;	/* What results were written [uncond] */
	__u32	stx_blksize;	/* Preferred general I/O size [uncond] */
	__u64	stx_attributes;	/* Flags conveying information about the file [uncond] */
	/* 0x10 */
	__u32	stx_nlink;	/* Number of hard links */
	__u32	stx_uid;	/* User ID of owner */
	__u32	stx_gid;	/* Group ID of owner */
	__u16	stx_mode;	/* File mode */
	__u16	__spare0[1];
	/* 0x20 */
	__u64	stx_ino;	/* Inode number */
	__u64	stx_size;	/* File size */
	__u64	stx_blocks;	/* Number of 512-byte blocks allocated */
	__u64	stx_attributes_mask; /* Mask to show what's supported in stx_attributes */
	/* 0x40 */
	struct statx_timestamp	stx_atime;	/* Last access time */
	struct statx_timestamp	stx_btime;	/* File creation time */
	struct statx_timestamp	stx_ctime;	/* Last attribute change time */
	struct statx_timestamp	stx_mtime;	/* Last data modification time */
	/* 0x80 */
	__u32	stx_rdev_major;	/* Device ID of special file [if bdev/cdev] */
	__u32	stx_rdev_minor;
	__u32	stx_dev_major;	/* ID of device containing file [uncond] */
	__u32	stx_dev_minor;
	/* 0x90 */
	__u64	stx_mnt_id;
	__u32	stx_dio_mem_align;	/* Memory buffer alignment for direct I/O */
	__u32	stx_dio_offset_align;	/* File offset alignment for direct I/O */
	/* 0xa0 */
	__u64	stx_subvol;	/* Subvolume identifier */
	__u32	stx_atomic_write_unit_min;	/* Min atomic write unit in bytes */
	__u32	stx_atomic_write_unit_max;	/* Max atomic write unit in bytes */
	/* 0xb0 */
	__u32   stx_atomic_write_segments_max;	/* Max atomic write segment count */

	/* File offset alignment for direct I/O reads */
	__u32	stx_dio_read_offset_align;

	/* 0xb8 */
	/* Optimised max atomic write unit in bytes */
	__u32	stx_atomic_write_unit_max_opt;
	__u32	__spare2[1];
	/* 0xc0 */
	__u64	__spare3[8];	/* Spare space for future expansion */
	/* 0x100 */
};

static inline ssize_t
statx(
	int		dfd,
	const char	*filename,
	unsigned int	flags,
	unsigned int	mask,
	struct statx	*buffer)
{
#ifdef __NR_statx
	return syscall(__NR_statx, dfd, filename, flags, mask, buffer);
#else
	errno = ENOSYS;
	return -1;
#endif
}

#endif /* OVERRIDE_SYSTEM_STATX */

#ifndef STATX_TYPE
/*
 * Flags to be stx_mask
 *
 * Query request/result mask for statx() and struct statx::stx_mask.
 *
 * These bits should be set in the mask argument of statx() to request
 * particular items when calling statx().
 */
#define STATX_TYPE		0x00000001U	/* Want/got stx_mode & S_IFMT */
#define STATX_MODE		0x00000002U	/* Want/got stx_mode & ~S_IFMT */
#define STATX_NLINK		0x00000004U	/* Want/got stx_nlink */
#define STATX_UID		0x00000008U	/* Want/got stx_uid */
#define STATX_GID		0x00000010U	/* Want/got stx_gid */
#define STATX_ATIME		0x00000020U	/* Want/got stx_atime */
#define STATX_MTIME		0x00000040U	/* Want/got stx_mtime */
#define STATX_CTIME		0x00000080U	/* Want/got stx_ctime */
#define STATX_INO		0x00000100U	/* Want/got stx_ino */
#define STATX_SIZE		0x00000200U	/* Want/got stx_size */
#define STATX_BLOCKS		0x00000400U	/* Want/got stx_blocks */
#define STATX_BASIC_STATS	0x000007ffU	/* The stuff in the normal stat struct */
#define STATX_BTIME		0x00000800U	/* Want/got stx_btime */

/*
 * This is deprecated, and shall remain the same value in the future.  To avoid
 * confusion please use the equivalent (STATX_BASIC_STATS | STATX_BTIME)
 * instead.
 */
#define STATX_ALL		0x00000fffU

/*
 * Attributes to be found in stx_attributes
 *
 * These give information about the features or the state of a file that might
 * be of use to ordinary userspace programs such as GUIs or ls rather than
 * specialised tools.
 *
 * Note that the flags marked [I] correspond to generic FS_IOC_FLAGS
 * semantically.  Where possible, the numerical value is picked to correspond
 * also.
 */
#define STATX_ATTR_COMPRESSED		0x00000004 /* [I] File is compressed by the fs */
#define STATX_ATTR_IMMUTABLE		0x00000010 /* [I] File is marked immutable */
#define STATX_ATTR_APPEND		0x00000020 /* [I] File is append-only */
#define STATX_ATTR_NODUMP		0x00000040 /* [I] File is not to be dumped */
#define STATX_ATTR_ENCRYPTED		0x00000800 /* [I] File requires key to decrypt in fs */

#define STATX_ATTR_AUTOMOUNT		0x00001000 /* Dir: Automount trigger */

#endif /* STATX_TYPE */

#ifndef STATX__RESERVED
#define STATX__RESERVED		0x80000000U	/* Reserved for future struct statx expansion */
#endif

#ifndef STATX_MNT_ID
#define STATX_MNT_ID		0x00001000U	/* Got stx_mnt_id */
#endif

#ifndef STATX_DIOALIGN
#define STATX_DIOALIGN		0x00002000U	/* Want/got direct I/O alignment info */
#endif

#ifndef STATX_MNT_ID_UNIQUE
#define STATX_MNT_ID_UNIQUE	0x00004000U	/* Want/got extended stx_mount_id */
#endif

#ifndef STATX_SUBVOL
#define STATX_SUBVOL		0x00008000U	/* Want/got stx_subvol */
#endif

#ifndef STATX_WRITE_ATOMIC
#define STATX_WRITE_ATOMIC	0x00010000U	/* Want/got atomic_write_* fields */
#endif

#ifndef STATX_DIO_READ_ALIGN
#define STATX_DIO_READ_ALIGN	0x00020000U	/* Want/got dio read alignment info */
#endif

#endif /* XFS_IO_STATX_H */
