chiark / gitweb /
Prep v228: With most functions split out, clean up the enormous includes list in...
[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 #if 0 /// UNNEEDED by elogind
102 ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
103         char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
104         _cleanup_close_ int fd = -1;
105         ssize_t l;
106
107         /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
108
109         fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
110         if (fd < 0)
111                 return -errno;
112
113         xsprintf(fn, "/proc/self/fd/%i", fd);
114
115         l = getxattr(fn, attribute, value, size);
116         if (l < 0)
117                 return -errno;
118
119         return l;
120 }
121
122 static int parse_crtime(le64_t le, usec_t *usec) {
123         uint64_t u;
124
125         assert(usec);
126
127         u = le64toh(le);
128         if (u == 0 || u == (uint64_t) -1)
129                 return -EIO;
130
131         *usec = (usec_t) u;
132         return 0;
133 }
134
135 int fd_getcrtime(int fd, usec_t *usec) {
136         le64_t le;
137         ssize_t n;
138
139         assert(fd >= 0);
140         assert(usec);
141
142         /* Until Linux gets a real concept of birthtime/creation time,
143          * let's fake one with xattrs */
144
145         n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le));
146         if (n < 0)
147                 return -errno;
148         if (n != sizeof(le))
149                 return -EIO;
150
151         return parse_crtime(le, usec);
152 }
153
154 int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
155         le64_t le;
156         ssize_t n;
157
158         n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags);
159         if (n < 0)
160                 return -errno;
161         if (n != sizeof(le))
162                 return -EIO;
163
164         return parse_crtime(le, usec);
165 }
166
167 int path_getcrtime(const char *p, usec_t *usec) {
168         le64_t le;
169         ssize_t n;
170
171         assert(p);
172         assert(usec);
173
174         n = getxattr(p, "user.crtime_usec", &le, sizeof(le));
175         if (n < 0)
176                 return -errno;
177         if (n != sizeof(le))
178                 return -EIO;
179
180         return parse_crtime(le, usec);
181 }
182
183 int fd_setcrtime(int fd, usec_t usec) {
184         le64_t le;
185
186         assert(fd >= 0);
187
188         if (usec <= 0)
189                 usec = now(CLOCK_REALTIME);
190
191         le = htole64((uint64_t) usec);
192         if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0)
193                 return -errno;
194
195         return 0;
196 }
197 #endif // 0