xref: /qemu/hw/9pfs/9p-xattr.c (revision 99dbfd1d)
1 /*
2  * 9p  xattr callback
3  *
4  * Copyright IBM, Corp. 2010
5  *
6  * Authors:
7  * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  *
12  */
13 
14 #include "qemu/osdep.h"
15 #include "9p.h"
16 #include "fsdev/file-op-9p.h"
17 #include "9p-xattr.h"
18 #include "9p-util.h"
19 #include "9p-local.h"
20 
21 
22 static XattrOperations *get_xattr_operations(XattrOperations **h,
23                                              const char *name)
24 {
25     XattrOperations *xops;
26     for (xops = *(h)++; xops != NULL; xops = *(h)++) {
27         if (!strncmp(name, xops->name, strlen(xops->name))) {
28             return xops;
29         }
30     }
31     return NULL;
32 }
33 
34 ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
35                        const char *name, void *value, size_t size)
36 {
37     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
38     if (xops) {
39         return xops->getxattr(ctx, path, name, value, size);
40     }
41     errno = EOPNOTSUPP;
42     return -1;
43 }
44 
45 ssize_t pt_listxattr(FsContext *ctx, const char *path,
46                      char *name, void *value, size_t size)
47 {
48     int name_size = strlen(name) + 1;
49     if (!value) {
50         return name_size;
51     }
52 
53     if (size < name_size) {
54         errno = ERANGE;
55         return -1;
56     }
57 
58     /* no need for strncpy: name_size is strlen(name)+1 */
59     memcpy(value, name, name_size);
60     return name_size;
61 }
62 
63 static ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
64                                      char *list, size_t size)
65 {
66     char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
67     int ret;
68 
69     ret = llistxattr(proc_path, list, size);
70     g_free(proc_path);
71     return ret;
72 }
73 
74 /*
75  * Get the list and pass to each layer to find out whether
76  * to send the data or not
77  */
78 ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
79                         void *value, size_t vsize)
80 {
81     ssize_t size = 0;
82     void *ovalue = value;
83     XattrOperations *xops;
84     char *orig_value, *orig_value_start;
85     ssize_t xattr_len, parsed_len = 0, attr_len;
86     char *dirpath, *name;
87     int dirfd;
88 
89     /* Get the actual len */
90     dirpath = g_path_get_dirname(path);
91     dirfd = local_opendir_nofollow(ctx, dirpath);
92     g_free(dirpath);
93     if (dirfd == -1) {
94         return -1;
95     }
96 
97     name = g_path_get_basename(path);
98     xattr_len = flistxattrat_nofollow(dirfd, name, value, 0);
99     if (xattr_len <= 0) {
100         g_free(name);
101         close_preserve_errno(dirfd);
102         return xattr_len;
103     }
104 
105     /* Now fetch the xattr and find the actual size */
106     orig_value = g_malloc(xattr_len);
107     xattr_len = flistxattrat_nofollow(dirfd, name, orig_value, xattr_len);
108     g_free(name);
109     close_preserve_errno(dirfd);
110     if (xattr_len < 0) {
111         return -1;
112     }
113 
114     /* store the orig pointer */
115     orig_value_start = orig_value;
116     while (xattr_len > parsed_len) {
117         xops = get_xattr_operations(ctx->xops, orig_value);
118         if (!xops) {
119             goto next_entry;
120         }
121 
122         if (!value) {
123             size += xops->listxattr(ctx, path, orig_value, value, vsize);
124         } else {
125             size = xops->listxattr(ctx, path, orig_value, value, vsize);
126             if (size < 0) {
127                 goto err_out;
128             }
129             value += size;
130             vsize -= size;
131         }
132 next_entry:
133         /* Got the next entry */
134         attr_len = strlen(orig_value) + 1;
135         parsed_len += attr_len;
136         orig_value += attr_len;
137     }
138     if (value) {
139         size = value - ovalue;
140     }
141 
142 err_out:
143     g_free(orig_value_start);
144     return size;
145 }
146 
147 int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
148                    void *value, size_t size, int flags)
149 {
150     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
151     if (xops) {
152         return xops->setxattr(ctx, path, name, value, size, flags);
153     }
154     errno = EOPNOTSUPP;
155     return -1;
156 
157 }
158 
159 int v9fs_remove_xattr(FsContext *ctx,
160                       const char *path, const char *name)
161 {
162     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
163     if (xops) {
164         return xops->removexattr(ctx, path, name);
165     }
166     errno = EOPNOTSUPP;
167     return -1;
168 
169 }
170 
171 ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
172                                 const char *name, void *value, size_t size)
173 {
174     char *dirpath = g_path_get_dirname(path);
175     char *filename = g_path_get_basename(path);
176     int dirfd;
177     ssize_t ret = -1;
178 
179     dirfd = local_opendir_nofollow(ctx, dirpath);
180     if (dirfd == -1) {
181         goto out;
182     }
183 
184     ret = fgetxattrat_nofollow(dirfd, filename, name, value, size);
185     close_preserve_errno(dirfd);
186 out:
187     g_free(dirpath);
188     g_free(filename);
189     return ret;
190 }
191 
192 ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name,
193                     void *value, size_t size)
194 {
195     return local_getxattr_nofollow(ctx, path, name, value, size);
196 }
197 
198 int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
199                          void *value, size_t size, int flags)
200 {
201     char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
202     int ret;
203 
204     ret = lsetxattr(proc_path, name, value, size, flags);
205     g_free(proc_path);
206     return ret;
207 }
208 
209 ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path,
210                                 const char *name, void *value, size_t size,
211                                 int flags)
212 {
213     char *dirpath = g_path_get_dirname(path);
214     char *filename = g_path_get_basename(path);
215     int dirfd;
216     ssize_t ret = -1;
217 
218     dirfd = local_opendir_nofollow(ctx, dirpath);
219     if (dirfd == -1) {
220         goto out;
221     }
222 
223     ret = fsetxattrat_nofollow(dirfd, filename, name, value, size, flags);
224     close_preserve_errno(dirfd);
225 out:
226     g_free(dirpath);
227     g_free(filename);
228     return ret;
229 }
230 
231 int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value,
232                 size_t size, int flags)
233 {
234     return local_setxattr_nofollow(ctx, path, name, value, size, flags);
235 }
236 
237 static ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
238                                        const char *name)
239 {
240     char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
241     int ret;
242 
243     ret = lremovexattr(proc_path, name);
244     g_free(proc_path);
245     return ret;
246 }
247 
248 ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
249                                    const char *name)
250 {
251     char *dirpath = g_path_get_dirname(path);
252     char *filename = g_path_get_basename(path);
253     int dirfd;
254     ssize_t ret = -1;
255 
256     dirfd = local_opendir_nofollow(ctx, dirpath);
257     if (dirfd == -1) {
258         goto out;
259     }
260 
261     ret = fremovexattrat_nofollow(dirfd, filename, name);
262     close_preserve_errno(dirfd);
263 out:
264     g_free(dirpath);
265     g_free(filename);
266     return ret;
267 }
268 
269 int pt_removexattr(FsContext *ctx, const char *path, const char *name)
270 {
271     return local_removexattr_nofollow(ctx, path, name);
272 }
273 
274 ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name,
275                         void *value, size_t size)
276 {
277     errno = ENOTSUP;
278     return -1;
279 }
280 
281 int notsup_setxattr(FsContext *ctx, const char *path, const char *name,
282                     void *value, size_t size, int flags)
283 {
284     errno = ENOTSUP;
285     return -1;
286 }
287 
288 ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name,
289                          void *value, size_t size)
290 {
291     return 0;
292 }
293 
294 int notsup_removexattr(FsContext *ctx, const char *path, const char *name)
295 {
296     errno = ENOTSUP;
297     return -1;
298 }
299 
300 XattrOperations *mapped_xattr_ops[] = {
301     &mapped_user_xattr,
302     &mapped_pacl_xattr,
303     &mapped_dacl_xattr,
304     NULL,
305 };
306 
307 XattrOperations *passthrough_xattr_ops[] = {
308     &passthrough_user_xattr,
309     &passthrough_acl_xattr,
310     NULL,
311 };
312 
313 /* for .user none model should be same as passthrough */
314 XattrOperations *none_xattr_ops[] = {
315     &passthrough_user_xattr,
316     &none_acl_xattr,
317     NULL,
318 };
319