1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
10 //#include <linux/stat.h>
15 #include <sys/xattr.h>
17 #include "alloc-util.h"
20 //#include "missing.h"
21 #include "sparse-endian.h"
22 #include "stdio-util.h"
23 //#include "string-util.h"
24 #include "time-util.h"
25 #include "xattr-util.h"
27 int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) {
36 for (l = 100; ; l = (size_t) n + 1) {
42 n = lgetxattr(path, name, v, l);
44 n = getxattr(path, name, v, l);
46 if (n >= 0 && (size_t) n < l) {
53 if (n < 0 && errno != ERANGE)
57 n = lgetxattr(path, name, NULL, 0);
59 n = getxattr(path, name, NULL, 0);
65 int fgetxattr_malloc(int fd, const char *name, char **value) {
74 for (l = 100; ; l = (size_t) n + 1) {
79 n = fgetxattr(fd, name, v, l);
81 if (n >= 0 && (size_t) n < l) {
88 if (n < 0 && errno != ERANGE)
91 n = fgetxattr(fd, name, NULL, 0);
97 #if 0 /// UNNEEDED by elogind
100 const char *filename,
101 const char *attribute,
102 void *value, size_t size,
106 char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
107 _cleanup_close_ int fd = -1;
110 /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
112 if (flags & ~(AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH))
115 if (isempty(filename)) {
116 if (!(flags & AT_EMPTY_PATH))
119 xsprintf(fn, "/proc/self/fd/%i", dirfd);
121 fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
125 xsprintf(fn, "/proc/self/fd/%i", fd);
128 l = getxattr(fn, attribute, value, size);
136 static int parse_crtime(le64_t le, usec_t *usec) {
142 if (IN_SET(u, 0, (uint64_t) -1))
149 int fd_getcrtime_at(int dirfd, const char *name, usec_t *ret, int flags) {
158 if (flags & ~(AT_EMPTY_PATH|AT_SYMLINK_NOFOLLOW))
161 /* So here's the deal: the creation/birth time (crtime/btime) of a file is a relatively newly supported concept
162 * on Linux (or more strictly speaking: a concept that only recently got supported in the API, it was
163 * implemented on various file systems on the lower level since a while, but never was accessible). However, we
164 * needed a concept like that for vaccuuming algorithms and such, hence we emulated it via a user xattr for a
165 * long time. Starting with Linux 4.11 there's statx() which exposes the timestamp to userspace for the first
166 * time, where it is available. Thius function will read it, but it tries to keep some compatibility with older
167 * systems: we try to read both the crtime/btime and the xattr, and then use whatever is older. After all the
168 * concept is useful for determining how "old" a file really is, and hence using the older of the two makes
171 if (statx(dirfd, strempty(name), flags|AT_STATX_DONT_SYNC, STATX_BTIME, &sx) >= 0 &&
172 (sx.stx_mask & STATX_BTIME) &&
173 sx.stx_btime.tv_sec != 0)
174 a = (usec_t) sx.stx_btime.tv_sec * USEC_PER_SEC +
175 (usec_t) sx.stx_btime.tv_nsec / NSEC_PER_USEC;
179 r = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags, &n);
184 r = parse_crtime(le, &b);
187 if (a != USEC_INFINITY) {
195 if (a != USEC_INFINITY)
203 int fd_getcrtime(int fd, usec_t *ret) {
204 return fd_getcrtime_at(fd, NULL, ret, AT_EMPTY_PATH);
207 int path_getcrtime(const char *p, usec_t *ret) {
208 return fd_getcrtime_at(AT_FDCWD, p, ret, 0);
211 int fd_setcrtime(int fd, usec_t usec) {
216 if (IN_SET(usec, 0, USEC_INFINITY))
217 usec = now(CLOCK_REALTIME);
219 le = htole64((uint64_t) usec);
220 if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0)