chiark / gitweb /
85f3d20604c088ea9faf9ab10af42be17c0e7f5c
[elogind.git] / src / basic / xattr-util.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2010 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/time.h>
26 #include <sys/xattr.h>
27
28 #include "alloc-util.h"
29 #include "fd-util.h"
30 #include "macro.h"
31 #include "sparse-endian.h"
32 #include "stdio-util.h"
33 #include "time-util.h"
34 #include "xattr-util.h"
35
36 int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) {
37         char *v;
38         size_t l;
39         ssize_t n;
40
41         assert(path);
42         assert(name);
43         assert(value);
44
45         for (l = 100; ; l = (size_t) n + 1) {
46                 v = new0(char, l);
47                 if (!v)
48                         return -ENOMEM;
49
50                 if (allow_symlink)
51                         n = lgetxattr(path, name, v, l);
52                 else
53                         n = getxattr(path, name, v, l);
54
55                 if (n >= 0 && (size_t) n < l) {
56                         *value = v;
57                         return n;
58                 }
59
60                 free(v);
61
62                 if (n < 0 && errno != ERANGE)
63                         return -errno;
64
65                 if (allow_symlink)
66                         n = lgetxattr(path, name, NULL, 0);
67                 else
68                         n = getxattr(path, name, NULL, 0);
69                 if (n < 0)
70                         return -errno;
71         }
72 }
73
74 int fgetxattr_malloc(int fd, const char *name, char **value) {
75         char *v;
76         size_t l;
77         ssize_t n;
78
79         assert(fd >= 0);
80         assert(name);
81         assert(value);
82
83         for (l = 100; ; l = (size_t) n + 1) {
84                 v = new0(char, l);
85                 if (!v)
86                         return -ENOMEM;
87
88                 n = fgetxattr(fd, name, v, l);
89
90                 if (n >= 0 && (size_t) n < l) {
91                         *value = v;
92                         return n;
93                 }
94
95                 free(v);
96
97                 if (n < 0 && errno != ERANGE)
98                         return -errno;
99
100                 n = fgetxattr(fd, name, NULL, 0);
101                 if (n < 0)
102                         return -errno;
103         }
104 }
105
106 #if 0 /// UNNEEDED by elogind
107 ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
108         char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
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
114         fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
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
127 static int parse_crtime(le64_t le, usec_t *usec) {
128         uint64_t u;
129
130         assert(usec);
131
132         u = le64toh(le);
133         if (u == 0 || u == (uint64_t) -1)
134                 return -EIO;
135
136         *usec = (usec_t) u;
137         return 0;
138 }
139
140 int 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
159 int 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
172 int 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
188 int 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 }
202 #endif // 0