xref: /qemu/hw/9pfs/9p-xattr.c (revision 56ad3e54)
1267ae092SWei Liu /*
2267ae092SWei Liu  * 9p  xattr callback
3267ae092SWei Liu  *
4267ae092SWei Liu  * Copyright IBM, Corp. 2010
5267ae092SWei Liu  *
6267ae092SWei Liu  * Authors:
7267ae092SWei Liu  * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
8267ae092SWei Liu  *
9267ae092SWei Liu  * This work is licensed under the terms of the GNU GPL, version 2.  See
10267ae092SWei Liu  * the COPYING file in the top-level directory.
11267ae092SWei Liu  *
12267ae092SWei Liu  */
13267ae092SWei Liu 
14fbc04127SPeter Maydell #include "qemu/osdep.h"
15ebe74f8bSWei Liu #include "9p.h"
16267ae092SWei Liu #include "fsdev/file-op-9p.h"
17267ae092SWei Liu #include "9p-xattr.h"
18*56ad3e54SGreg Kurz #include "9p-util.h"
19*56ad3e54SGreg Kurz #include "9p-local.h"
20267ae092SWei Liu 
21267ae092SWei Liu 
22267ae092SWei Liu static XattrOperations *get_xattr_operations(XattrOperations **h,
23267ae092SWei Liu                                              const char *name)
24267ae092SWei Liu {
25267ae092SWei Liu     XattrOperations *xops;
26267ae092SWei Liu     for (xops = *(h)++; xops != NULL; xops = *(h)++) {
27267ae092SWei Liu         if (!strncmp(name, xops->name, strlen(xops->name))) {
28267ae092SWei Liu             return xops;
29267ae092SWei Liu         }
30267ae092SWei Liu     }
31267ae092SWei Liu     return NULL;
32267ae092SWei Liu }
33267ae092SWei Liu 
34267ae092SWei Liu ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
35267ae092SWei Liu                        const char *name, void *value, size_t size)
36267ae092SWei Liu {
37267ae092SWei Liu     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
38267ae092SWei Liu     if (xops) {
39267ae092SWei Liu         return xops->getxattr(ctx, path, name, value, size);
40267ae092SWei Liu     }
41267ae092SWei Liu     errno = EOPNOTSUPP;
42267ae092SWei Liu     return -1;
43267ae092SWei Liu }
44267ae092SWei Liu 
45267ae092SWei Liu ssize_t pt_listxattr(FsContext *ctx, const char *path,
46267ae092SWei Liu                      char *name, void *value, size_t size)
47267ae092SWei Liu {
48267ae092SWei Liu     int name_size = strlen(name) + 1;
49267ae092SWei Liu     if (!value) {
50267ae092SWei Liu         return name_size;
51267ae092SWei Liu     }
52267ae092SWei Liu 
53267ae092SWei Liu     if (size < name_size) {
54267ae092SWei Liu         errno = ERANGE;
55267ae092SWei Liu         return -1;
56267ae092SWei Liu     }
57267ae092SWei Liu 
58267ae092SWei Liu     /* no need for strncpy: name_size is strlen(name)+1 */
59267ae092SWei Liu     memcpy(value, name, name_size);
60267ae092SWei Liu     return name_size;
61267ae092SWei Liu }
62267ae092SWei Liu 
63267ae092SWei Liu 
64267ae092SWei Liu /*
65267ae092SWei Liu  * Get the list and pass to each layer to find out whether
66267ae092SWei Liu  * to send the data or not
67267ae092SWei Liu  */
68267ae092SWei Liu ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
69267ae092SWei Liu                         void *value, size_t vsize)
70267ae092SWei Liu {
71267ae092SWei Liu     ssize_t size = 0;
72267ae092SWei Liu     char *buffer;
73267ae092SWei Liu     void *ovalue = value;
74267ae092SWei Liu     XattrOperations *xops;
75267ae092SWei Liu     char *orig_value, *orig_value_start;
76267ae092SWei Liu     ssize_t xattr_len, parsed_len = 0, attr_len;
77267ae092SWei Liu 
78267ae092SWei Liu     /* Get the actual len */
79267ae092SWei Liu     buffer = rpath(ctx, path);
80267ae092SWei Liu     xattr_len = llistxattr(buffer, value, 0);
81267ae092SWei Liu     if (xattr_len <= 0) {
82267ae092SWei Liu         g_free(buffer);
83267ae092SWei Liu         return xattr_len;
84267ae092SWei Liu     }
85267ae092SWei Liu 
86267ae092SWei Liu     /* Now fetch the xattr and find the actual size */
87267ae092SWei Liu     orig_value = g_malloc(xattr_len);
88267ae092SWei Liu     xattr_len = llistxattr(buffer, orig_value, xattr_len);
89267ae092SWei Liu     g_free(buffer);
90267ae092SWei Liu 
91267ae092SWei Liu     /* store the orig pointer */
92267ae092SWei Liu     orig_value_start = orig_value;
93267ae092SWei Liu     while (xattr_len > parsed_len) {
94267ae092SWei Liu         xops = get_xattr_operations(ctx->xops, orig_value);
95267ae092SWei Liu         if (!xops) {
96267ae092SWei Liu             goto next_entry;
97267ae092SWei Liu         }
98267ae092SWei Liu 
99267ae092SWei Liu         if (!value) {
100267ae092SWei Liu             size += xops->listxattr(ctx, path, orig_value, value, vsize);
101267ae092SWei Liu         } else {
102267ae092SWei Liu             size = xops->listxattr(ctx, path, orig_value, value, vsize);
103267ae092SWei Liu             if (size < 0) {
104267ae092SWei Liu                 goto err_out;
105267ae092SWei Liu             }
106267ae092SWei Liu             value += size;
107267ae092SWei Liu             vsize -= size;
108267ae092SWei Liu         }
109267ae092SWei Liu next_entry:
110267ae092SWei Liu         /* Got the next entry */
111267ae092SWei Liu         attr_len = strlen(orig_value) + 1;
112267ae092SWei Liu         parsed_len += attr_len;
113267ae092SWei Liu         orig_value += attr_len;
114267ae092SWei Liu     }
115267ae092SWei Liu     if (value) {
116267ae092SWei Liu         size = value - ovalue;
117267ae092SWei Liu     }
118267ae092SWei Liu 
119267ae092SWei Liu err_out:
120267ae092SWei Liu     g_free(orig_value_start);
121267ae092SWei Liu     return size;
122267ae092SWei Liu }
123267ae092SWei Liu 
124267ae092SWei Liu int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
125267ae092SWei Liu                    void *value, size_t size, int flags)
126267ae092SWei Liu {
127267ae092SWei Liu     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
128267ae092SWei Liu     if (xops) {
129267ae092SWei Liu         return xops->setxattr(ctx, path, name, value, size, flags);
130267ae092SWei Liu     }
131267ae092SWei Liu     errno = EOPNOTSUPP;
132267ae092SWei Liu     return -1;
133267ae092SWei Liu 
134267ae092SWei Liu }
135267ae092SWei Liu 
136267ae092SWei Liu int v9fs_remove_xattr(FsContext *ctx,
137267ae092SWei Liu                       const char *path, const char *name)
138267ae092SWei Liu {
139267ae092SWei Liu     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
140267ae092SWei Liu     if (xops) {
141267ae092SWei Liu         return xops->removexattr(ctx, path, name);
142267ae092SWei Liu     }
143267ae092SWei Liu     errno = EOPNOTSUPP;
144267ae092SWei Liu     return -1;
145267ae092SWei Liu 
146267ae092SWei Liu }
147267ae092SWei Liu 
148*56ad3e54SGreg Kurz ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
149*56ad3e54SGreg Kurz                                 const char *name, void *value, size_t size)
150*56ad3e54SGreg Kurz {
151*56ad3e54SGreg Kurz     char *dirpath = g_path_get_dirname(path);
152*56ad3e54SGreg Kurz     char *filename = g_path_get_basename(path);
153*56ad3e54SGreg Kurz     int dirfd;
154*56ad3e54SGreg Kurz     ssize_t ret = -1;
155*56ad3e54SGreg Kurz 
156*56ad3e54SGreg Kurz     dirfd = local_opendir_nofollow(ctx, dirpath);
157*56ad3e54SGreg Kurz     if (dirfd == -1) {
158*56ad3e54SGreg Kurz         goto out;
159*56ad3e54SGreg Kurz     }
160*56ad3e54SGreg Kurz 
161*56ad3e54SGreg Kurz     ret = fgetxattrat_nofollow(dirfd, filename, name, value, size);
162*56ad3e54SGreg Kurz     close_preserve_errno(dirfd);
163*56ad3e54SGreg Kurz out:
164*56ad3e54SGreg Kurz     g_free(dirpath);
165*56ad3e54SGreg Kurz     g_free(filename);
166*56ad3e54SGreg Kurz     return ret;
167*56ad3e54SGreg Kurz }
168*56ad3e54SGreg Kurz 
16956fc494bSGreg Kurz ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name,
17056fc494bSGreg Kurz                     void *value, size_t size)
17156fc494bSGreg Kurz {
172*56ad3e54SGreg Kurz     return local_getxattr_nofollow(ctx, path, name, value, size);
17356fc494bSGreg Kurz }
17456fc494bSGreg Kurz 
17556fc494bSGreg Kurz int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value,
17656fc494bSGreg Kurz                 size_t size, int flags)
17756fc494bSGreg Kurz {
17856fc494bSGreg Kurz     char *buffer;
17956fc494bSGreg Kurz     int ret;
18056fc494bSGreg Kurz 
18156fc494bSGreg Kurz     buffer = rpath(ctx, path);
18256fc494bSGreg Kurz     ret = lsetxattr(buffer, name, value, size, flags);
18356fc494bSGreg Kurz     g_free(buffer);
18456fc494bSGreg Kurz     return ret;
18556fc494bSGreg Kurz }
18656fc494bSGreg Kurz 
18756fc494bSGreg Kurz int pt_removexattr(FsContext *ctx, const char *path, const char *name)
18856fc494bSGreg Kurz {
18956fc494bSGreg Kurz     char *buffer;
19056fc494bSGreg Kurz     int ret;
19156fc494bSGreg Kurz 
19256fc494bSGreg Kurz     buffer = rpath(ctx, path);
19356fc494bSGreg Kurz     ret = lremovexattr(path, name);
19456fc494bSGreg Kurz     g_free(buffer);
19556fc494bSGreg Kurz     return ret;
19656fc494bSGreg Kurz }
19756fc494bSGreg Kurz 
19856fc494bSGreg Kurz ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name,
19956fc494bSGreg Kurz                         void *value, size_t size)
20056fc494bSGreg Kurz {
20156fc494bSGreg Kurz     errno = ENOTSUP;
20256fc494bSGreg Kurz     return -1;
20356fc494bSGreg Kurz }
20456fc494bSGreg Kurz 
20556fc494bSGreg Kurz int notsup_setxattr(FsContext *ctx, const char *path, const char *name,
20656fc494bSGreg Kurz                     void *value, size_t size, int flags)
20756fc494bSGreg Kurz {
20856fc494bSGreg Kurz     errno = ENOTSUP;
20956fc494bSGreg Kurz     return -1;
21056fc494bSGreg Kurz }
21156fc494bSGreg Kurz 
21256fc494bSGreg Kurz ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name,
21356fc494bSGreg Kurz                          void *value, size_t size)
21456fc494bSGreg Kurz {
21556fc494bSGreg Kurz     return 0;
21656fc494bSGreg Kurz }
21756fc494bSGreg Kurz 
21856fc494bSGreg Kurz int notsup_removexattr(FsContext *ctx, const char *path, const char *name)
21956fc494bSGreg Kurz {
22056fc494bSGreg Kurz     errno = ENOTSUP;
22156fc494bSGreg Kurz     return -1;
22256fc494bSGreg Kurz }
22356fc494bSGreg Kurz 
224267ae092SWei Liu XattrOperations *mapped_xattr_ops[] = {
225267ae092SWei Liu     &mapped_user_xattr,
226267ae092SWei Liu     &mapped_pacl_xattr,
227267ae092SWei Liu     &mapped_dacl_xattr,
228267ae092SWei Liu     NULL,
229267ae092SWei Liu };
230267ae092SWei Liu 
231267ae092SWei Liu XattrOperations *passthrough_xattr_ops[] = {
232267ae092SWei Liu     &passthrough_user_xattr,
233267ae092SWei Liu     &passthrough_acl_xattr,
234267ae092SWei Liu     NULL,
235267ae092SWei Liu };
236267ae092SWei Liu 
237267ae092SWei Liu /* for .user none model should be same as passthrough */
238267ae092SWei Liu XattrOperations *none_xattr_ops[] = {
239267ae092SWei Liu     &passthrough_user_xattr,
240267ae092SWei Liu     &none_acl_xattr,
241267ae092SWei Liu     NULL,
242267ae092SWei Liu };
243