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