xref: /qemu/hw/9pfs/9p-xattr.c (revision abff1abf)
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 /*
64  * Get the list and pass to each layer to find out whether
65  * to send the data or not
66  */
67 ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
68                         void *value, size_t vsize)
69 {
70     ssize_t size = 0;
71     void *ovalue = value;
72     XattrOperations *xops;
73     char *orig_value, *orig_value_start;
74     ssize_t xattr_len, parsed_len = 0, attr_len;
75     char *dirpath, *name;
76     int dirfd;
77 
78     /* Get the actual len */
79     dirpath = g_path_get_dirname(path);
80     dirfd = local_opendir_nofollow(ctx, dirpath);
81     g_free(dirpath);
82     if (dirfd == -1) {
83         return -1;
84     }
85 
86     name = g_path_get_basename(path);
87     xattr_len = flistxattrat_nofollow(dirfd, name, value, 0);
88     if (xattr_len <= 0) {
89         g_free(name);
90         close_preserve_errno(dirfd);
91         return xattr_len;
92     }
93 
94     /* Now fetch the xattr and find the actual size */
95     orig_value = g_malloc(xattr_len);
96     xattr_len = flistxattrat_nofollow(dirfd, name, orig_value, xattr_len);
97     g_free(name);
98     close_preserve_errno(dirfd);
99     if (xattr_len < 0) {
100         g_free(orig_value);
101         return -1;
102     }
103 
104     /* store the orig pointer */
105     orig_value_start = orig_value;
106     while (xattr_len > parsed_len) {
107         xops = get_xattr_operations(ctx->xops, orig_value);
108         if (!xops) {
109             goto next_entry;
110         }
111 
112         if (!value) {
113             size += xops->listxattr(ctx, path, orig_value, value, vsize);
114         } else {
115             size = xops->listxattr(ctx, path, orig_value, value, vsize);
116             if (size < 0) {
117                 goto err_out;
118             }
119             value += size;
120             vsize -= size;
121         }
122 next_entry:
123         /* Got the next entry */
124         attr_len = strlen(orig_value) + 1;
125         parsed_len += attr_len;
126         orig_value += attr_len;
127     }
128     if (value) {
129         size = value - ovalue;
130     }
131 
132 err_out:
133     g_free(orig_value_start);
134     return size;
135 }
136 
137 int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
138                    void *value, size_t size, int flags)
139 {
140     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
141     if (xops) {
142         return xops->setxattr(ctx, path, name, value, size, flags);
143     }
144     errno = EOPNOTSUPP;
145     return -1;
146 
147 }
148 
149 int v9fs_remove_xattr(FsContext *ctx,
150                       const char *path, const char *name)
151 {
152     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
153     if (xops) {
154         return xops->removexattr(ctx, path, name);
155     }
156     errno = EOPNOTSUPP;
157     return -1;
158 
159 }
160 
161 ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
162                                 const char *name, void *value, size_t size)
163 {
164     char *dirpath = g_path_get_dirname(path);
165     char *filename = g_path_get_basename(path);
166     int dirfd;
167     ssize_t ret = -1;
168 
169     dirfd = local_opendir_nofollow(ctx, dirpath);
170     if (dirfd == -1) {
171         goto out;
172     }
173 
174     ret = fgetxattrat_nofollow(dirfd, filename, name, value, size);
175     close_preserve_errno(dirfd);
176 out:
177     g_free(dirpath);
178     g_free(filename);
179     return ret;
180 }
181 
182 ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name,
183                     void *value, size_t size)
184 {
185     return local_getxattr_nofollow(ctx, path, name, value, size);
186 }
187 
188 ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path,
189                                 const char *name, void *value, size_t size,
190                                 int flags)
191 {
192     char *dirpath = g_path_get_dirname(path);
193     char *filename = g_path_get_basename(path);
194     int dirfd;
195     ssize_t ret = -1;
196 
197     dirfd = local_opendir_nofollow(ctx, dirpath);
198     if (dirfd == -1) {
199         goto out;
200     }
201 
202     ret = fsetxattrat_nofollow(dirfd, filename, name, value, size, flags);
203     close_preserve_errno(dirfd);
204 out:
205     g_free(dirpath);
206     g_free(filename);
207     return ret;
208 }
209 
210 int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value,
211                 size_t size, int flags)
212 {
213     return local_setxattr_nofollow(ctx, path, name, value, size, flags);
214 }
215 
216 ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
217                                    const char *name)
218 {
219     char *dirpath = g_path_get_dirname(path);
220     char *filename = g_path_get_basename(path);
221     int dirfd;
222     ssize_t ret = -1;
223 
224     dirfd = local_opendir_nofollow(ctx, dirpath);
225     if (dirfd == -1) {
226         goto out;
227     }
228 
229     ret = fremovexattrat_nofollow(dirfd, filename, name);
230     close_preserve_errno(dirfd);
231 out:
232     g_free(dirpath);
233     g_free(filename);
234     return ret;
235 }
236 
237 int pt_removexattr(FsContext *ctx, const char *path, const char *name)
238 {
239     return local_removexattr_nofollow(ctx, path, name);
240 }
241 
242 ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name,
243                         void *value, size_t size)
244 {
245     errno = ENOTSUP;
246     return -1;
247 }
248 
249 int notsup_setxattr(FsContext *ctx, const char *path, const char *name,
250                     void *value, size_t size, int flags)
251 {
252     errno = ENOTSUP;
253     return -1;
254 }
255 
256 ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name,
257                          void *value, size_t size)
258 {
259     return 0;
260 }
261 
262 int notsup_removexattr(FsContext *ctx, const char *path, const char *name)
263 {
264     errno = ENOTSUP;
265     return -1;
266 }
267 
268 XattrOperations *mapped_xattr_ops[] = {
269     &mapped_user_xattr,
270     &mapped_pacl_xattr,
271     &mapped_dacl_xattr,
272     NULL,
273 };
274 
275 XattrOperations *passthrough_xattr_ops[] = {
276     &passthrough_user_xattr,
277     &passthrough_acl_xattr,
278     NULL,
279 };
280 
281 /* for .user none model should be same as passthrough */
282 XattrOperations *none_xattr_ops[] = {
283     &passthrough_user_xattr,
284     &none_acl_xattr,
285     NULL,
286 };
287