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