chiark / gitweb /
Prep v228: Add remaining updates from upstream (2/3)
[elogind.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 <sys/xattr.h>
23
24 #include "alloc-util.h"
25 #include "fd-util.h"
26 #include "sparse-endian.h"
27 #include "stdio-util.h"
28 #include "util.h"
29 #include "xattr-util.h"
30
31 int 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
69 int 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
101 ssize_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
121 /// UNNEEDED by elogind
122 #if 0
123 static int parse_crtime(le64_t le, usec_t *usec) {
124         uint64_t u;
125
126         assert(usec);
127
128         u = le64toh(le);
129         if (u == 0 || u == (uint64_t) -1)
130                 return -EIO;
131
132         *usec = (usec_t) u;
133         return 0;
134 }
135
136 int fd_getcrtime(int fd, usec_t *usec) {
137         le64_t le;
138         ssize_t n;
139
140         assert(fd >= 0);
141         assert(usec);
142
143         /* Until Linux gets a real concept of birthtime/creation time,
144          * let's fake one with xattrs */
145
146         n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le));
147         if (n < 0)
148                 return -errno;
149         if (n != sizeof(le))
150                 return -EIO;
151
152         return parse_crtime(le, usec);
153 }
154
155 int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
156         le64_t le;
157         ssize_t n;
158
159         n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags);
160         if (n < 0)
161                 return -errno;
162         if (n != sizeof(le))
163                 return -EIO;
164
165         return parse_crtime(le, usec);
166 }
167
168 int path_getcrtime(const char *p, usec_t *usec) {
169         le64_t le;
170         ssize_t n;
171
172         assert(p);
173         assert(usec);
174
175         n = getxattr(p, "user.crtime_usec", &le, sizeof(le));
176         if (n < 0)
177                 return -errno;
178         if (n != sizeof(le))
179                 return -EIO;
180
181         return parse_crtime(le, usec);
182 }
183
184 int fd_setcrtime(int fd, usec_t usec) {
185         le64_t le;
186
187         assert(fd >= 0);
188
189         if (usec <= 0)
190                 usec = now(CLOCK_REALTIME);
191
192         le = htole64((uint64_t) usec);
193         if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0)
194                 return -errno;
195
196         return 0;
197 }
198 #endif // 0