]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/xattr-util.c
tree-wide: make use of new STRLEN() macro everywhere (#7639)
[thirdparty/systemd.git] / src / basic / xattr-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
89a5a90c
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
11c3a366
TA
21#include <errno.h>
22#include <fcntl.h>
23#include <stdint.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/time.h>
89a5a90c
LP
27#include <sys/xattr.h>
28
b5efdb8a 29#include "alloc-util.h"
89a5a90c 30#include "fd-util.h"
11c3a366 31#include "macro.h"
93cc7779 32#include "sparse-endian.h"
15a5e950 33#include "stdio-util.h"
93cc7779 34#include "time-util.h"
89a5a90c
LP
35#include "xattr-util.h"
36
37int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) {
38 char *v;
39 size_t l;
40 ssize_t n;
41
42 assert(path);
43 assert(name);
44 assert(value);
45
46 for (l = 100; ; l = (size_t) n + 1) {
47 v = new0(char, l);
48 if (!v)
49 return -ENOMEM;
50
51 if (allow_symlink)
52 n = lgetxattr(path, name, v, l);
53 else
54 n = getxattr(path, name, v, l);
55
56 if (n >= 0 && (size_t) n < l) {
57 *value = v;
58 return n;
59 }
60
61 free(v);
62
63 if (n < 0 && errno != ERANGE)
64 return -errno;
65
66 if (allow_symlink)
67 n = lgetxattr(path, name, NULL, 0);
68 else
69 n = getxattr(path, name, NULL, 0);
70 if (n < 0)
71 return -errno;
72 }
73}
74
75int fgetxattr_malloc(int fd, const char *name, char **value) {
76 char *v;
77 size_t l;
78 ssize_t n;
79
80 assert(fd >= 0);
81 assert(name);
82 assert(value);
83
84 for (l = 100; ; l = (size_t) n + 1) {
85 v = new0(char, l);
86 if (!v)
87 return -ENOMEM;
88
89 n = fgetxattr(fd, name, v, l);
90
91 if (n >= 0 && (size_t) n < l) {
92 *value = v;
93 return n;
94 }
95
96 free(v);
97
98 if (n < 0 && errno != ERANGE)
99 return -errno;
100
101 n = fgetxattr(fd, name, NULL, 0);
102 if (n < 0)
103 return -errno;
104 }
105}
106
107ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
fbd0b64f 108 char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
89a5a90c
LP
109 _cleanup_close_ int fd = -1;
110 ssize_t l;
111
112 /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
113
c4b69156 114 fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
89a5a90c
LP
115 if (fd < 0)
116 return -errno;
117
118 xsprintf(fn, "/proc/self/fd/%i", fd);
119
120 l = getxattr(fn, attribute, value, size);
121 if (l < 0)
122 return -errno;
123
124 return l;
125}
126
127static int parse_crtime(le64_t le, usec_t *usec) {
128 uint64_t u;
129
130 assert(usec);
131
132 u = le64toh(le);
4c701096 133 if (IN_SET(u, 0, (uint64_t) -1))
89a5a90c
LP
134 return -EIO;
135
136 *usec = (usec_t) u;
137 return 0;
138}
139
140int fd_getcrtime(int fd, usec_t *usec) {
141 le64_t le;
142 ssize_t n;
143
144 assert(fd >= 0);
145 assert(usec);
146
147 /* Until Linux gets a real concept of birthtime/creation time,
148 * let's fake one with xattrs */
149
150 n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le));
151 if (n < 0)
152 return -errno;
153 if (n != sizeof(le))
154 return -EIO;
155
156 return parse_crtime(le, usec);
157}
158
159int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
160 le64_t le;
161 ssize_t n;
162
163 n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags);
164 if (n < 0)
165 return -errno;
166 if (n != sizeof(le))
167 return -EIO;
168
169 return parse_crtime(le, usec);
170}
171
172int path_getcrtime(const char *p, usec_t *usec) {
173 le64_t le;
174 ssize_t n;
175
176 assert(p);
177 assert(usec);
178
179 n = getxattr(p, "user.crtime_usec", &le, sizeof(le));
180 if (n < 0)
181 return -errno;
182 if (n != sizeof(le))
183 return -EIO;
184
185 return parse_crtime(le, usec);
186}
187
188int fd_setcrtime(int fd, usec_t usec) {
189 le64_t le;
190
191 assert(fd >= 0);
192
193 if (usec <= 0)
194 usec = now(CLOCK_REALTIME);
195
196 le = htole64((uint64_t) usec);
197 if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0)
198 return -errno;
199
200 return 0;
201}