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