]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/xattr-util.c
Merge pull request #2054 from keszybz/nss-link-less-2
[thirdparty/systemd.git] / src / basic / xattr-util.c
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 <errno.h>
23 #include <fcntl.h>
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/time.h>
28 #include <sys/xattr.h>
29
30 #include "alloc-util.h"
31 #include "fd-util.h"
32 #include "macro.h"
33 #include "sparse-endian.h"
34 #include "stdio-util.h"
35 #include "time-util.h"
36 #include "xattr-util.h"
37
38 int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) {
39 char *v;
40 size_t l;
41 ssize_t n;
42
43 assert(path);
44 assert(name);
45 assert(value);
46
47 for (l = 100; ; l = (size_t) n + 1) {
48 v = new0(char, l);
49 if (!v)
50 return -ENOMEM;
51
52 if (allow_symlink)
53 n = lgetxattr(path, name, v, l);
54 else
55 n = getxattr(path, name, v, l);
56
57 if (n >= 0 && (size_t) n < l) {
58 *value = v;
59 return n;
60 }
61
62 free(v);
63
64 if (n < 0 && errno != ERANGE)
65 return -errno;
66
67 if (allow_symlink)
68 n = lgetxattr(path, name, NULL, 0);
69 else
70 n = getxattr(path, name, NULL, 0);
71 if (n < 0)
72 return -errno;
73 }
74 }
75
76 int fgetxattr_malloc(int fd, const char *name, char **value) {
77 char *v;
78 size_t l;
79 ssize_t n;
80
81 assert(fd >= 0);
82 assert(name);
83 assert(value);
84
85 for (l = 100; ; l = (size_t) n + 1) {
86 v = new0(char, l);
87 if (!v)
88 return -ENOMEM;
89
90 n = fgetxattr(fd, name, v, l);
91
92 if (n >= 0 && (size_t) n < l) {
93 *value = v;
94 return n;
95 }
96
97 free(v);
98
99 if (n < 0 && errno != ERANGE)
100 return -errno;
101
102 n = fgetxattr(fd, name, NULL, 0);
103 if (n < 0)
104 return -errno;
105 }
106 }
107
108 ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
109 char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
110 _cleanup_close_ int fd = -1;
111 ssize_t l;
112
113 /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
114
115 fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
116 if (fd < 0)
117 return -errno;
118
119 xsprintf(fn, "/proc/self/fd/%i", fd);
120
121 l = getxattr(fn, attribute, value, size);
122 if (l < 0)
123 return -errno;
124
125 return l;
126 }
127
128 static int parse_crtime(le64_t le, usec_t *usec) {
129 uint64_t u;
130
131 assert(usec);
132
133 u = le64toh(le);
134 if (u == 0 || u == (uint64_t) -1)
135 return -EIO;
136
137 *usec = (usec_t) u;
138 return 0;
139 }
140
141 int fd_getcrtime(int fd, usec_t *usec) {
142 le64_t le;
143 ssize_t n;
144
145 assert(fd >= 0);
146 assert(usec);
147
148 /* Until Linux gets a real concept of birthtime/creation time,
149 * let's fake one with xattrs */
150
151 n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le));
152 if (n < 0)
153 return -errno;
154 if (n != sizeof(le))
155 return -EIO;
156
157 return parse_crtime(le, usec);
158 }
159
160 int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
161 le64_t le;
162 ssize_t n;
163
164 n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags);
165 if (n < 0)
166 return -errno;
167 if (n != sizeof(le))
168 return -EIO;
169
170 return parse_crtime(le, usec);
171 }
172
173 int path_getcrtime(const char *p, usec_t *usec) {
174 le64_t le;
175 ssize_t n;
176
177 assert(p);
178 assert(usec);
179
180 n = getxattr(p, "user.crtime_usec", &le, sizeof(le));
181 if (n < 0)
182 return -errno;
183 if (n != sizeof(le))
184 return -EIO;
185
186 return parse_crtime(le, usec);
187 }
188
189 int fd_setcrtime(int fd, usec_t usec) {
190 le64_t le;
191
192 assert(fd >= 0);
193
194 if (usec <= 0)
195 usec = now(CLOCK_REALTIME);
196
197 le = htole64((uint64_t) usec);
198 if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0)
199 return -errno;
200
201 return 0;
202 }