#include <uchar.h>
#include <linux/ethtool.h>
#include <linux/fib_rules.h>
+//#include <linux/stat.h>
+//#include <sys/stat.h>
'''
# FIXME: key_serial_t is only defined in keyutils.h, this is bound to fail
'key_serial_t',
'struct ethtool_link_settings',
'struct fib_rule_uid_range',
+ 'struct statx',
]
# We get -1 if the size cannot be determined
foreach ident : [
['memfd_create', '''#include <sys/mman.h>'''],
['gettid', '''#include <sys/types.h>
-// #include <unistd.h>'''],
+ #include <unistd.h>'''],
['pivot_root', '''#include <stdlib.h>
#include <unistd.h>'''], # no known header declares pivot_root
['name_to_handle_at', '''#include <sys/types.h>
['bpf', '''#include <sys/syscall.h>
#include <unistd.h>'''],
['explicit_bzero' , '''#include <string.h>'''],
+ ['statx', '''#include <sys/types.h>
+ #include <sys/stat.h>
+// #include <unistd.h>'''],
]
have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE')
#include <inttypes.h>
#include <linux/audit.h>
#include <linux/capability.h>
+//#include <linux/falloc.h>
#include <linux/if_link.h>
#include <linux/input.h>
#include <linux/loop.h>
#include <linux/neighbour.h>
#include <linux/oom.h>
#include <linux/rtnetlink.h>
+//#include <linux/stat.h>
#include <net/ethernet.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/socket.h>
+//#include <sys/stat.h>
#include <sys/syscall.h>
#include <uchar.h>
#include <unistd.h>
#define BPF_FS_MAGIC 0xcafe4a11
#endif
+#ifndef OCFS2_SUPER_MAGIC
+#define OCFS2_SUPER_MAGIC 0x7461636f
+#endif
+
#ifndef MS_MOVE
#define MS_MOVE 8192
#endif
#define NS_GET_NSTYPE _IO(0xb7, 0x3)
#endif
+#ifndef FALLOC_FL_KEEP_SIZE
+#define FALLOC_FL_KEEP_SIZE 0x01
+#endif
+
+#ifndef FALLOC_FL_PUNCH_HOLE
+#define FALLOC_FL_PUNCH_HOLE 0x02
+#endif
+
#ifndef PF_KTHREAD
#define PF_KTHREAD 0x00200000
#endif
+#if ! HAVE_STRUCT_STATX
+struct statx_timestamp {
+ int64_t tv_sec;
+ uint32_t tv_nsec;
+ uint32_t __reserved;
+};
+struct statx {
+ uint32_t stx_mask;
+ uint32_t stx_blksize;
+ uint64_t stx_attributes;
+ uint32_t stx_nlink;
+ uint32_t stx_uid;
+ uint32_t stx_gid;
+ uint16_t stx_mode;
+ uint16_t __spare0[1];
+ uint64_t stx_ino;
+ uint64_t stx_size;
+ uint64_t stx_blocks;
+ uint64_t stx_attributes_mask;
+ struct statx_timestamp stx_atime;
+ struct statx_timestamp stx_btime;
+ struct statx_timestamp stx_ctime;
+ struct statx_timestamp stx_mtime;
+ uint32_t stx_rdev_major;
+ uint32_t stx_rdev_minor;
+ uint32_t stx_dev_major;
+ uint32_t stx_dev_minor;
+ uint64_t __spare2[14];
+};
+#endif
+
+#ifndef STATX_BTIME
+#define STATX_BTIME 0x00000800U
+#endif
+
+#ifndef AT_STATX_DONT_SYNC
+#define AT_STATX_DONT_SYNC 0x4000
+#endif
+
#include "missing_syscall.h"
#include <sys/types.h>
#if !HAVE_PIVOT_ROOT
-static inline int missing_pivot_root(const char *new_root, const char *put_old) {
+static inline int pivot_root(const char *new_root, const char *put_old) {
return syscall(SYS_pivot_root, new_root, put_old);
}
-
-# define pivot_root missing_pivot_root
#endif
#endif // 0
# endif
# endif
-static inline int missing_memfd_create(const char *name, unsigned int flags) {
+static inline int memfd_create(const char *name, unsigned int flags) {
# ifdef __NR_memfd_create
return syscall(__NR_memfd_create, name, flags);
# else
return -1;
# endif
}
-
-# define memfd_create missing_memfd_create
#endif
/* ======================================================================= */
# endif
# endif
-static inline int missing_getrandom(void *buffer, size_t count, unsigned flags) {
+static inline int getrandom(void *buffer, size_t count, unsigned flags) {
# ifdef __NR_getrandom
return syscall(__NR_getrandom, buffer, count, flags);
# else
return -1;
# endif
}
-
-# define getrandom missing_getrandom
#endif
/* ======================================================================= */
#if !HAVE_GETTID
-static inline pid_t missing_gettid(void) {
+static inline pid_t gettid(void) {
return (pid_t) syscall(SYS_gettid);
}
-
-# define gettid missing_gettid
#endif
/* ======================================================================= */
unsigned char f_handle[0];
};
-static inline int missing_name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) {
+static inline int name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) {
# ifdef __NR_name_to_handle_at
return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags);
# else
return -1;
# endif
}
-
-# define name_to_handle_at missing_name_to_handle_at
#endif
/* ======================================================================= */
# endif
# endif
-static inline int missing_setns(int fd, int nstype) {
+static inline int setns(int fd, int nstype) {
# ifdef __NR_setns
return syscall(__NR_setns, fd, nstype);
# else
return -1;
# endif
}
-
-# define setns missing_setns
#endif
/* ======================================================================= */
# endif
# endif
-static inline int missing_renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) {
+static inline int renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) {
# ifdef __NR_renameat2
return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags);
# else
return -1;
# endif
}
-
-# define renameat2 missing_renameat2
#endif
/* ======================================================================= */
#if !HAVE_KCMP
-static inline int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
+static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
# ifdef __NR_kcmp
return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
# else
return -1;
# endif
}
-
-# define kcmp missing_kcmp
#endif
-
/* ======================================================================= */
#if !HAVE_KEYCTL
-static inline long missing_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) {
+static inline long keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) {
# ifdef __NR_keyctl
return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5);
# else
errno = ENOSYS;
return -1;
# endif
-
-# define keyctl missing_keyctl
}
-static inline key_serial_t missing_add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) {
+static inline key_serial_t add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) {
# ifdef __NR_add_key
return syscall(__NR_add_key, type, description, payload, plen, ringid);
# else
errno = ENOSYS;
return -1;
# endif
-
-# define add_key missing_add_key
}
-static inline key_serial_t missing_request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) {
+static inline key_serial_t request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) {
# ifdef __NR_request_key
return syscall(__NR_request_key, type, description, callout_info, destringid);
# else
errno = ENOSYS;
return -1;
# endif
-
-# define request_key missing_request_key
}
#endif
# endif
# endif
-static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in,
- int fd_out, loff_t *off_out,
- size_t len,
- unsigned int flags) {
+static inline ssize_t copy_file_range(int fd_in, loff_t *off_in,
+ int fd_out, loff_t *off_out,
+ size_t len,
+ unsigned int flags) {
# ifdef __NR_copy_file_range
return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags);
# else
return -1;
# endif
}
-
-# define copy_file_range missing_copy_file_range
#endif
/* ======================================================================= */
union bpf_attr;
-static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) {
+static inline int bpf(int cmd, union bpf_attr *attr, size_t size) {
#ifdef __NR_bpf
return (int) syscall(__NR_bpf, cmd, attr, size);
#else
#endif
}
-# define bpf missing_bpf
#endif
/* ======================================================================= */
# endif
# endif
#endif
+
+#if !HAVE_STATX
+# ifndef __NR_statx
+# if defined __i386__
+# define __NR_bpf 383
+# elif defined __x86_64__
+# define __NR_bpf 332
+# else
+# warning "__NR_statx not defined for your architecture"
+# endif
+# endif
+
+struct statx;
+
+static inline ssize_t statx(int dfd, const char *filename, unsigned 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
#include <errno.h>
#include <fcntl.h>
+//#include <linux/stat.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "alloc-util.h"
#include "fd-util.h"
#include "macro.h"
+//#include "missing.h"
#include "sparse-endian.h"
#include "stdio-util.h"
//#include "string-util.h"
return 0;
}
-int fd_getcrtime(int fd, usec_t *usec) {
+int fd_getcrtime_at(int dirfd, const char *name, usec_t *ret, int flags) {
+ struct statx sx;
+ usec_t a, b;
le64_t le;
ssize_t n;
+ int r;
- assert(fd >= 0);
- assert(usec);
-
- /* Until Linux gets a real concept of birthtime/creation time,
- * let's fake one with xattrs */
-
- n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le));
- if (n < 0)
- return -errno;
- if (n != sizeof(le))
- return -EIO;
+ assert(ret);
- return parse_crtime(le, usec);
-}
+ if (flags & ~(AT_EMPTY_PATH|AT_SYMLINK_NOFOLLOW))
+ return -EINVAL;
-int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
- le64_t le;
- ssize_t n;
+ /* So here's the deal: the creation/birth time (crtime/btime) of a file is a relatively newly supported concept
+ * on Linux (or more strictly speaking: a concept that only recently got supported in the API, it was
+ * implemented on various file systems on the lower level since a while, but never was accessible). However, we
+ * needed a concept like that for vaccuuming algorithms and such, hence we emulated it via a user xattr for a
+ * long time. Starting with Linux 4.11 there's statx() which exposes the timestamp to userspace for the first
+ * time, where it is available. Thius function will read it, but it tries to keep some compatibility with older
+ * systems: we try to read both the crtime/btime and the xattr, and then use whatever is older. After all the
+ * concept is useful for determining how "old" a file really is, and hence using the older of the two makes
+ * most sense. */
+
+ if (statx(dirfd, strempty(name), flags|AT_STATX_DONT_SYNC, STATX_BTIME, &sx) >= 0 &&
+ (sx.stx_mask & STATX_BTIME) &&
+ sx.stx_btime.tv_sec != 0)
+ a = (usec_t) sx.stx_btime.tv_sec * USEC_PER_SEC +
+ (usec_t) sx.stx_btime.tv_nsec / NSEC_PER_USEC;
+ else
+ a = USEC_INFINITY;
n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags);
if (n < 0)
- return -errno;
- if (n != sizeof(le))
- return -EIO;
+ r = -errno;
+ else if (n != sizeof(le))
+ r = -EIO;
+ else
+ r = parse_crtime(le, &b);
+ if (r < 0) {
+ if (a != USEC_INFINITY) {
+ *ret = a;
+ return 0;
+ }
- return parse_crtime(le, usec);
-}
+ return r;
+ }
-int path_getcrtime(const char *p, usec_t *usec) {
- le64_t le;
- ssize_t n;
+ if (a != USEC_INFINITY)
+ *ret = MIN(a, b);
+ else
+ *ret = b;
- assert(p);
- assert(usec);
+ return 0;
+}
- n = getxattr(p, "user.crtime_usec", &le, sizeof(le));
- if (n < 0)
- return -errno;
- if (n != sizeof(le))
- return -EIO;
+int fd_getcrtime(int fd, usec_t *ret) {
+ return fd_getcrtime_at(fd, NULL, ret, AT_EMPTY_PATH);
+}
- return parse_crtime(le, usec);
+int path_getcrtime(const char *p, usec_t *ret) {
+ return fd_getcrtime_at(AT_FDCWD, p, ret, 0);
}
int fd_setcrtime(int fd, usec_t usec) {
assert(fd >= 0);
- if (usec <= 0)
+ if (IN_SET(usec, 0, USEC_INFINITY))
usec = now(CLOCK_REALTIME);
le = htole64((uint64_t) usec);