]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
xattr-util: modernize getcrtime_at() and friends
authorMike Yuan <me@yhndnzj.com>
Sun, 26 Jan 2025 16:46:30 +0000 (17:46 +0100)
committerMike Yuan <me@yhndnzj.com>
Sun, 9 Feb 2025 13:51:03 +0000 (14:51 +0100)
- Drop fd_ prefix for openat()-like function
- Make fd_setcrtime() accept O_PATH fds too
- Use statx_timestamp_load()

src/basic/xattr-util.c
src/basic/xattr-util.h
src/libsystemd/sd-journal/journal-vacuum.c

index 896d85bf5cc791073b6da4eee1a260d5147845be..a68cff79860521b8ae9206d4d3174e2b657d43eb 100644 (file)
@@ -133,94 +133,6 @@ int getxattr_at_bool(int fd, const char *path, const char *name, int flags) {
         return parse_boolean(v);
 }
 
-static int parse_crtime(le64_t le, usec_t *usec) {
-        uint64_t u;
-
-        assert(usec);
-
-        u = le64toh(le);
-        if (IN_SET(u, 0, UINT64_MAX))
-                return -EIO;
-
-        *usec = (usec_t) u;
-        return 0;
-}
-
-int fd_getcrtime_at(
-                int fd,
-                const char *path,
-                int flags,
-                usec_t *ret) {
-
-        _cleanup_free_ le64_t *le = NULL;
-        STRUCT_STATX_DEFINE(sx);
-        usec_t a, b;
-        int r;
-
-        assert(fd >= 0 || fd == AT_FDCWD);
-        assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
-        assert(ret);
-
-        if (!path)
-                flags |= AT_EMPTY_PATH;
-
-        /* 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 vacuuming 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. This 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(fd, strempty(path),
-                  at_flags_normalize_nofollow(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;
-
-        r = getxattr_at_malloc(fd, path, "user.crtime_usec", flags, (char**) &le);
-        if (r >= 0) {
-                if (r != sizeof(*le))
-                        r = -EIO;
-                else
-                        r = parse_crtime(*le, &b);
-        }
-        if (r < 0) {
-                if (a != USEC_INFINITY) {
-                        *ret = a;
-                        return 0;
-                }
-
-                return r;
-        }
-
-        if (a != USEC_INFINITY)
-                *ret = MIN(a, b);
-        else
-                *ret = b;
-
-        return 0;
-}
-
-int fd_setcrtime(int fd, usec_t usec) {
-        le64_t le;
-
-        assert(fd >= 0);
-
-        if (!timestamp_is_set(usec))
-                usec = now(CLOCK_REALTIME);
-
-        le = htole64((uint64_t) usec);
-        return RET_NERRNO(fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0));
-}
-
 int listxattr_at_malloc(
                 int fd,
                 const char *path,
@@ -377,3 +289,89 @@ int xsetxattr(int fd,
 
         return 0;
 }
+
+static int parse_crtime(le64_t le, usec_t *ret) {
+        usec_t u;
+
+        assert(ret);
+
+        assert_cc(sizeof(usec_t) == sizeof(uint64_t));
+        assert_cc((usec_t) UINT64_MAX == USEC_INFINITY);
+
+        u = (usec_t) le64toh(le);
+        if (!timestamp_is_set(u))
+                return -EIO;
+
+        *ret = u;
+        return 0;
+}
+
+int getcrtime_at(
+                int fd,
+                const char *path,
+                int at_flags,
+                usec_t *ret) {
+
+        _cleanup_free_ le64_t *le = NULL;
+        STRUCT_STATX_DEFINE(sx);
+        usec_t a, b;
+        int r;
+
+        assert(fd >= 0 || fd == AT_FDCWD);
+        assert((at_flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
+
+        if (isempty(path))
+                at_flags |= AT_EMPTY_PATH;
+
+        /* 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 vacuuming 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. This 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(fd, strempty(path),
+                  at_flags_normalize_nofollow(at_flags)|AT_STATX_DONT_SYNC,
+                  STATX_BTIME,
+                  &sx) >= 0 &&
+            FLAGS_SET(sx.stx_mask, STATX_BTIME) && sx.stx_btime.tv_sec != 0)
+                a = statx_timestamp_load(&sx.stx_btime);
+        else
+                a = USEC_INFINITY;
+
+        r = getxattr_at_malloc(fd, path, "user.crtime_usec", at_flags, (char**) &le);
+        if (r >= 0) {
+                if (r != sizeof(*le))
+                        r = -EIO;
+                else
+                        r = parse_crtime(*le, &b);
+        }
+        if (r < 0) {
+                if (a != USEC_INFINITY) {
+                        if (ret)
+                                *ret = a;
+                        return 0;
+                }
+
+                return r;
+        }
+
+        if (ret)
+                *ret = MIN(a, b);
+        return 0;
+}
+
+int fd_setcrtime(int fd, usec_t usec) {
+        le64_t le;
+
+        assert(fd >= 0);
+
+        if (!timestamp_is_set(usec))
+                usec = now(CLOCK_REALTIME);
+
+        le = htole64((uint64_t) usec);
+        return xsetxattr(fd, /* path = */ NULL, "user.crtime_usec", (const char*) &le, sizeof(le), AT_EMPTY_PATH);
+}
index 17c3684280a2c7b0b8997c0e005e604e4e89ef5f..7d5aea30171fc9cdd0887afe89e02381c4a5ef8e 100644 (file)
@@ -20,13 +20,6 @@ static inline int fgetxattr_malloc(int fd, const char *name, char **ret) {
 
 int getxattr_at_bool(int fd, const char *path, const char *name, int flags);
 
-int fd_setcrtime(int fd, usec_t usec);
-
-int fd_getcrtime_at(int fd, const char *name, int flags, usec_t *ret);
-static inline int fd_getcrtime(int fd, usec_t *ret) {
-        return fd_getcrtime_at(fd, NULL, 0, ret);
-}
-
 int listxattr_at_malloc(int fd, const char *path, int flags, char **ret);
 static inline int listxattr_malloc(const char *path, char **ret) {
         return listxattr_at_malloc(AT_FDCWD, path, AT_SYMLINK_FOLLOW, ret);
@@ -39,3 +32,9 @@ static inline int flistxattr_malloc(int fd, char **ret) {
 }
 
 int xsetxattr(int fd, const char *path, const char *name, const char *value, size_t size, int flags);
+
+int fd_setcrtime(int fd, usec_t usec);
+int getcrtime_at(int fd, const char *path, int at_flags, usec_t *ret);
+static inline int fd_getcrtime(int fd, usec_t *ret) {
+        return getcrtime_at(fd, NULL, 0, ret);
+}
index 829edb31a70f51ea78a75f178ca0dd946c0e6d52..f7dee86209e73f4ae13f529a9a9d23651d47e7e5 100644 (file)
@@ -90,7 +90,7 @@ static void patch_realtime(
          * FS might provide, but unfortunately there's currently no sane API to query it. Hence let's
          * implement this manually... */
 
-        if (fd_getcrtime_at(fd, fn, AT_SYMLINK_FOLLOW, &x) >= 0 && x < *realtime)
+        if (getcrtime_at(fd, fn, AT_SYMLINK_FOLLOW, &x) >= 0 && x < *realtime)
                 *realtime = x;
 }